mirror of
https://github.com/hoornet/vega.git
synced 2026-05-07 20:59:12 -07:00
Add zaps: NWC wallet connect + NIP-57 zap flow
- NWC client (nwc.ts): parse URI, encrypt/send kind 23194, await kind 23195 response - Lightning store: persist NWC URI to localStorage, zap() via NDKZapper + lnPay callback - ZapModal: amount presets (21/100/500/1000/5000 sats), custom amount, optional comment, paying/success/error states, prompts to Settings if no wallet connected - ⚡ zap button on NoteCard (action row) and ProfileView (header, next to follow) - Settings > Lightning Wallet section: paste NWC URI, connect/disconnect Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
82
src/stores/lightning.ts
Normal file
82
src/stores/lightning.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { create } from "zustand";
|
||||
import { NDKEvent, NDKUser, NDKZapper, LnPayCb } from "@nostr-dev-kit/ndk";
|
||||
import { getNDK } from "../lib/nostr";
|
||||
import { payInvoiceViaNWC, isValidNwcUri } from "../lib/lightning/nwc";
|
||||
|
||||
const NWC_STORAGE_KEY = "wrystr_nwc_uri";
|
||||
|
||||
interface ZapTarget {
|
||||
type: "note";
|
||||
event: NDKEvent;
|
||||
recipientPubkey: string;
|
||||
recipientLud16?: string;
|
||||
}
|
||||
|
||||
interface ZapProfileTarget {
|
||||
type: "profile";
|
||||
pubkey: string;
|
||||
lud16?: string;
|
||||
}
|
||||
|
||||
export type ZapTargetSpec = ZapTarget | ZapProfileTarget;
|
||||
|
||||
interface LightningState {
|
||||
nwcUri: string | null;
|
||||
setNwcUri: (uri: string) => void;
|
||||
clearNwcUri: () => void;
|
||||
zap: (target: ZapTargetSpec, amountSats: number, comment?: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export const useLightningStore = create<LightningState>(() => ({
|
||||
nwcUri: localStorage.getItem(NWC_STORAGE_KEY),
|
||||
|
||||
setNwcUri: (uri: string) => {
|
||||
if (!isValidNwcUri(uri)) throw new Error("Invalid NWC URI");
|
||||
localStorage.setItem(NWC_STORAGE_KEY, uri);
|
||||
useLightningStore.setState({ nwcUri: uri });
|
||||
},
|
||||
|
||||
clearNwcUri: () => {
|
||||
localStorage.removeItem(NWC_STORAGE_KEY);
|
||||
useLightningStore.setState({ nwcUri: null });
|
||||
},
|
||||
|
||||
zap: async (targetSpec: ZapTargetSpec, amountSats: number, comment?: string) => {
|
||||
const { nwcUri } = useLightningStore.getState();
|
||||
if (!nwcUri) throw new Error("No wallet connected. Add an NWC connection in Settings.");
|
||||
|
||||
const ndk = getNDK();
|
||||
if (!ndk.signer) throw new Error("Not logged in");
|
||||
|
||||
let target: NDKEvent | NDKUser;
|
||||
if (targetSpec.type === "note") {
|
||||
target = targetSpec.event;
|
||||
} else {
|
||||
target = ndk.getUser({ pubkey: targetSpec.pubkey });
|
||||
}
|
||||
|
||||
const lnPay: LnPayCb = async ({ pr }) => {
|
||||
const preimage = await payInvoiceViaNWC(nwcUri, pr);
|
||||
return { preimage };
|
||||
};
|
||||
|
||||
const zapper = new NDKZapper(target, amountSats * 1000, "msat", {
|
||||
comment,
|
||||
lnPay,
|
||||
ndk,
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
zapper.on("complete", (results) => {
|
||||
const errors = Array.from(results.values()).filter((r) => r instanceof Error);
|
||||
if (errors.length > 0) {
|
||||
reject(errors[0]);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
zapper.zap().catch(reject);
|
||||
});
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user