mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
Requested: integrate getAlby/bitcoin-connect as a smooth NWC "connect wallet" front-end, keeping manual URI entry as backup. Plan (docs/bitcoin-connect-plan.md) grounds it in bitvid's existing NWC stack: BC's NWC connector exposes the raw pairing URI (provider.client.nostrWalletConnectUrl) which feeds the existing validateWalletUri → per-npub store → zap-split/pay_invoice pipeline unchanged. BC is a connect adapter, not a payment layer. Covers delivery (vendor+lazy import vs esm.sh; CSP already allows esm.sh), persistence ownership, NWC-only connector scope, least-privilege requestMethods, UI placement, FEATURE_BITCOIN_CONNECT flag, and the security constraints (bearer spending secret, Alpha lib pin/vendor). Co-Authored-By: Claude Opus 4.8 <[email protected]>
168 lines
9.2 KiB
Markdown
168 lines
9.2 KiB
Markdown
# Bitcoin Connect — NWC wallet connect UX — Dev Plan
|
||
|
||
Status: **DECISIONS NEEDED (D1–D6)** — no code yet. Adds Alby's
|
||
[Bitcoin Connect](https://bitcoin-connect.com/) as a smooth "connect your wallet"
|
||
front-end for NWC, feeding bitvid's **existing** NWC pipeline. Manual URI entry
|
||
stays as the backup/advanced path. Feature-flagged (off = no trace).
|
||
|
||
## Executive summary
|
||
|
||
bitvid already has a full NWC stack: manual URI entry (`#walletUri` in the Wallet
|
||
Connect pane → `ProfileWalletController`), validation
|
||
(`nwcSettingsService.validateWalletUri` — requires `nostr+walletconnect://`),
|
||
per-npub storage (`nwcSettings.js`, IndexedDB + localStorage), opt-in encrypted
|
||
cross-login sync, and the zap-split/pay_invoice payment pipeline
|
||
(`js/payments/*`). The friction is purely the *connect* step — pasting a URI.
|
||
|
||
Bitcoin Connect solves exactly that: a polished modal that walks the user through
|
||
connecting a wallet (CoinOS, Alby Hub, mutiny, etc.) and, for the NWC connector,
|
||
**exposes the raw NWC pairing URI**. So we bolt it on as an alternate connect
|
||
button that extracts the URI and hands it to bitvid's existing validate→store
|
||
pipeline. **No change to how bitvid pays or stores** — one new way to obtain the
|
||
same string. Manual entry stays for power users / unsupported wallets.
|
||
|
||
## How Bitcoin Connect works (verified against the v3 README)
|
||
|
||
- Package `@getalby/bitcoin-connect` (ESM; Lit web components + functions; bundles
|
||
`@getalby/js-sdk` internally — no separate peer dep). Also loadable from
|
||
`https://esm.sh/@getalby/bitcoin-connect@<pin>` (our CSP already allows esm.sh).
|
||
- `init({ appName, filters: ["nwc"], persistConnection, providerConfig: { nwc: {
|
||
authorizationUrlOptions: { requestMethods } } } })` — `filters:["nwc"]` restricts
|
||
the modal to NWC; `requestMethods` requests least-privilege scopes.
|
||
- `launchModal()` / `await requestProvider()` opens the connect flow.
|
||
- `onConnected((provider) => …)` → a WebLN provider. **NWC extraction:**
|
||
```js
|
||
import { onConnected } from "@getalby/bitcoin-connect";
|
||
import { WebLNProviders } from "@getalby/sdk"; // or the re-export
|
||
onConnected((provider) => {
|
||
if (provider instanceof WebLNProviders.NostrWebLNProvider) {
|
||
const uri = provider.client.nostrWalletConnectUrl; // ← the NWC secret
|
||
}
|
||
});
|
||
```
|
||
- `disconnect()` clears its connection; `getConnectorConfig()` returns the saved
|
||
connector config. Persistence to localStorage is automatic when
|
||
`persistConnection: true`.
|
||
- ⚠️ README says the lib is **Alpha** — pin an exact version.
|
||
|
||
## Decisions needed
|
||
|
||
> **DECISION 1 — Delivery. 🔵 NEEDED.**
|
||
> - **A — Vendor + lazy `import()`:** esbuild-bundle a pinned `@getalby/bitcoin-connect`
|
||
> into `vendor/bitcoin-connect.bundle.min.js` (same pattern as floating-ui in
|
||
> `scripts/build-beacon.mjs`), dynamically imported only when the user opens the
|
||
> Wallet pane / clicks Connect. Offline-safe, supply-chain-pinned, no main-bundle bloat.
|
||
> - **B — Lazy-load from esm.sh** (CSP already allows it) at a pinned version.
|
||
> Zero vendoring work, but a runtime CDN dependency + supply-chain trust.
|
||
> _Recommendation: **A** — bitvid vendors its other heavy deps; Bitcoin Connect is
|
||
> a Lit bundle (~hundreds of KB) so lazy-import is important either way._
|
||
|
||
> **DECISION 2 — Persistence ownership. 🔵 NEEDED.**
|
||
> - **A — `persistConnection: false`:** Bitcoin Connect is purely the connect UI;
|
||
> bitvid extracts the URI and is the ONLY store (its existing encrypted-sync /
|
||
> per-npub model). No duplicate plaintext copy in `bc:*` localStorage.
|
||
> - **B — let it persist** and rely on `disconnect()` on bitvid logout.
|
||
> _Recommendation: **A** — one owner of the spending secret; call `disconnect()`
|
||
> right after extracting to be safe._
|
||
|
||
> **DECISION 3 — Connector scope. 🔵 NEEDED.**
|
||
> - **A — NWC only** (`filters:["nwc"]`). Yields a URI that flows straight into the
|
||
> existing pipeline; zap-split/pay_invoice unchanged.
|
||
> - **B — also allow WebLN / Alby-extension / Alby Hub** connectors. Smoother for
|
||
> Alby users, but those give a WebLN *provider*, not an NWC URI — bitvid's raw-NWC
|
||
> payment pipeline can't consume them without a second WebLN payment path.
|
||
> _Recommendation: **A for v1** (matches the pipeline); a WebLN path is a separate
|
||
> later effort if there's demand._
|
||
|
||
> **DECISION 4 — Requested scopes. 🔵 NEEDED.**
|
||
> `requestMethods` to request from the wallet. bitvid needs **`pay_invoice`** (zaps);
|
||
> `get_balance` (balance display), `make_invoice` / `lookup_invoice` (receipts/tally).
|
||
> _Recommendation: `["pay_invoice","get_balance","make_invoice","lookup_invoice"]` —
|
||
> least privilege for what bitvid actually calls. (The wallet ultimately decides.)_
|
||
|
||
> **DECISION 5 — UI placement vs manual mode. 🔵 NEEDED.**
|
||
> _Recommendation: In the Wallet Connect pane, make **"Connect wallet"** (Bitcoin
|
||
> Connect) the primary CTA, and move the raw-URI field under a collapsible
|
||
> **"Advanced / paste a connection manually"** — manual stays a first-class backup,
|
||
> just de-emphasized. On success, populate the same status/disconnect UI._
|
||
|
||
> **DECISION 6 — Feature flag. 🔵 NEEDED.**
|
||
> _Recommendation: `FEATURE_BITCOIN_CONNECT` in `config/instance-config.js` (default
|
||
> off = no trace), wired exactly like `FEATURE_AUDIO_INGEST`. With it off, only the
|
||
> manual URI field shows — zero new code path or bundle load._
|
||
|
||
## Config flag (off = no trace)
|
||
|
||
- `FEATURE_BITCOIN_CONNECT` (default **false**) — gates the "Connect wallet" button
|
||
+ the lazy Bitcoin Connect import. Off ⇒ manual URI entry only (today's behavior).
|
||
|
||
## Integration points (small, contained)
|
||
|
||
- `components/profile-modal.html` — Wallet Connect pane: add the "Connect wallet"
|
||
button; wrap the existing `#walletUri` field as "Advanced/manual."
|
||
- `js/ui/profileModal/ProfileWalletController.js` — a `handleBitcoinConnect()` that
|
||
lazy-imports the lib, `init()`s once (NWC-only, least-privilege, no-persist),
|
||
`launchModal()`, and on `onConnected` extracts `nostrWalletConnectUrl` →
|
||
runs the SAME `validateWalletUri` + save path as manual "Save wallet" → then
|
||
`disconnect()`. Reuses all existing status/disconnect/sync UI.
|
||
- `config/instance-config.js` / `js/config.js` / `js/constants.js` — the flag.
|
||
- `scripts/` + `vendor/` — the esbuild vendor bundle (D1-A).
|
||
|
||
## Architecture
|
||
|
||
Bitcoin Connect is a **connect adapter**, not a payment layer:
|
||
```
|
||
[Connect wallet] → BC modal (NWC) → onConnected(provider)
|
||
→ provider.client.nostrWalletConnectUrl
|
||
→ validateWalletUri() (existing, scheme check)
|
||
→ nwcSettingsService save (existing: per-npub store + optional encrypted sync)
|
||
→ BC disconnect() (bitvid now owns the secret)
|
||
[zaps] → js/payments/nwcClient pay_invoice + zap-split (UNCHANGED)
|
||
```
|
||
The manual field writes to the exact same validate→store path, so the two entry
|
||
points converge immediately and everything downstream is untouched.
|
||
|
||
## Security (NWC URI = bearer SPENDING secret)
|
||
|
||
- **Never log** `nostrWalletConnectUrl` (or the provider) — extract → validate →
|
||
store via the existing (never-logged) pipeline; treat like the manual field.
|
||
- **`persistConnection: false` + `disconnect()`** after extract so the secret isn't
|
||
duplicated in Bitcoin Connect's own plaintext `bc:*` localStorage (D2).
|
||
- **Pin the version + vendor it** (Alpha lib) — no unpinned CDN `@latest`.
|
||
- **Least-privilege `requestMethods`** (D4) — request only what bitvid calls.
|
||
- Re-run bitvid's `validateWalletUri` on the extracted string; don't trust the lib
|
||
blindly. Keep the explicit "a wallet-connect URI can SPEND" warning on the
|
||
encrypted-sync toggle.
|
||
- Payment invariants unchanged: `PLATFORM_FEE_PERCENT=30` split, preimage
|
||
verification, and the "a pay_invoice timeout must NEVER auto-resend" rule all live
|
||
in `js/payments/*` and are not touched.
|
||
|
||
## Phases (flag-gated from day one)
|
||
|
||
- **Phase 0 — Flag + vendor bundle.** Add `FEATURE_BITCOIN_CONNECT` (off) and the
|
||
esbuild vendor step. No UX.
|
||
- **Phase 1 — Connect button (headline).** Wallet pane "Connect wallet" → BC NWC
|
||
modal → extract → existing save path → disconnect. Manual field → "Advanced."
|
||
- **Phase 2 — Polish.** Balance display (BC `showBalance` / get_balance), reconnect
|
||
affordance, and a "test connection" ping. Optional.
|
||
- **Phase 3 (only if wanted) — WebLN path** (D3-B): accept Alby-extension/Hub
|
||
connectors via a WebLN payment adapter alongside raw NWC. Separate effort.
|
||
|
||
## Risks / watch-items
|
||
|
||
- **Alpha library / breaking changes** — pin + vendor; wrap behind our own thin
|
||
adapter so an API change is a one-file fix.
|
||
- **Bundle weight** — lazy-import only on Wallet-pane open / button click.
|
||
- **Wallet grants fewer scopes than requested** — if `pay_invoice` isn't granted,
|
||
zaps fail; surface a clear error and fall back to manual.
|
||
- **Not all wallets support NWC** — manual mode + non-NWC connectors (D3-B) cover the gap.
|
||
- **esm.sh path (D1-B)** would add a runtime third-party origin to the trust surface.
|
||
|
||
## Sources
|
||
|
||
- getAlby/bitcoin-connect README (v3) — install, `init` filters/providerConfig,
|
||
`onConnected`, `NostrWebLNProvider.client.nostrWalletConnectUrl`, `disconnect`.
|
||
- bitcoin-connect.com. Related bitvid: `js/services/nwcSettingsService.js`,
|
||
`js/nwcSettings.js`, `js/ui/profileModal/ProfileWalletController.js`,
|
||
`js/payments/*`, `docs/audio-integration-plan.md` (flag-wiring pattern).
|