935c121bab
Replaces every kind 30223 surface with kind 33863 -- the self-authored fundraising campaign with a single `w` Bitcoin wallet endpoint. Hard cutoff: no migration, no dual-read, no legacy support. Schema (src/lib/campaign.ts): - `CAMPAIGN_KIND` constant bumped 30223 -> 33863. - New `CampaignWallet` type with `onchain` (`bc1q`/`bc1p`) and `sp` (`sp1`) modes, prefix-disambiguated. Bitcoin-mainnet only; testnet/regtest/lightning prefixes are rejected at parse time. - New `parseCampaignWallet()` validates bech32 via bitcoinjs-lib for on-chain addresses and shape-checks silent-payment codes. - `ParsedCampaign` drops `recipients`, `category`, `tags`, `location`, `archived`, `image` (-> `banner`), `goalSats` (-> `goalUsd`). Adds `wallet` and `bannerImeta` (parsed NIP-92). - `CAMPAIGN_CATEGORIES`, `CampaignCategory`, `LEGACY_CAMPAIGN_CATEGORY_ALIASES`, `getCampaignPrimaryTagLabel`, `splitDonation`, `minDonationForSplit`, `DonationSplit`, `CampaignRecipient` removed. Publishing (useDonateCampaign): - Single-output PSBT paying `campaign.wallet.value`. - Kind 8333 receipt has NO `p` tags -- campaigns are not Nostr-identity recipients. `i`, `amount`, `a`, `K`, `alt` only. - SP campaigns are refused with a clear error directing donors to external BIP-352-capable wallets via the on-page QR/copy panel. Verification (useOnchainZaps.verifyOnchainZap): - Two modes: identity-recipient (existing `p`-tag derivation) and campaign-wallet (match outputs against `campaign.w`). The branch is selected by whether the receipt has an `a` tag pointing at a kind 33863 campaign. SP-targeted receipts are rejected. Querying (useCampaigns, useAllCampaigns, useCampaignDonations): - Drop `category`, `recipientPubkeys`, `includeArchived` options. - `useCampaignDonations` now takes a `ParsedCampaign` and verifies every receipt on-chain against the campaign's `w` address before counting it. SP campaigns short-circuit to zeros. - Search drops `location` and `t`-tag branches; title/summary/story only. UI: - `CampaignCard`, `HeroCampaignSpotlight`, `CampaignsPage`: drop recipient counts, archived/category badges, `location`; use `banner`. Silent-payment campaigns render a "Private -- totals not public" notice instead of progress. - `CampaignDetailPage`: archive flow replaced with NIP-09 kind 5 deletion. Drops the multi-beneficiary recipient column. Donate column shows the in-app PSBT donate button (on-chain) plus the always- available external-wallet QR/copy panel. SP campaigns show the panel only -- no in-app donate. - `CreateCampaignPage`: drops Beneficiaries section, tag input, and USD-to-sats conversion. Adds a Wallet field with mode-aware validation hint. Goal is integer USD. Banner upload captures NIP-94 tags and converts to NIP-92 `imeta` at publish. - `DonateDialog`: collapses ~1200 LOC of split logic into a single- output flow. Form -> Confirm -> Success. Logged-out and signer- unsupported users are pointed at the external-wallet panel. - New `CampaignWalletDonatePanel` component (replaces the pubkey-derived `BeneficiaryDonateDialog`). QR + copy + open-in-wallet for any `bc1`/`sp1` endpoint, with mode-appropriate privacy notice. Removed: - `useArchiveCampaign` hook (closure via NIP-09 deletion only). - `ClaimPage` and its `/claim` route (claim-for-someone-else flow no longer applies -- campaigns are self-authored). - `BeneficiaryDonateDialog.tsx` (replaced by `CampaignWalletDonatePanel.tsx`). - Community-donate synthesis hack in `CommunityDetailPage` (no more fabricating a `ParsedCampaign` from community moderators). NIP.md was updated separately to specify Kind 33863.