mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-10 15:36:53 +02:00
feat: cache NWC get_info response to avoid redundant calls
- Add info$ BehaviorSubject observable to nwc.ts service for cached wallet info - Update WalletInfo type to include methods (required), network (optional) - Update useWallet hook to return cached info via use$(info$) - Update WalletViewer to use cached info instead of calling getInfo() on mount - Update ZapWindow to use cached info instead of calling getInfo() on mount - Update ConnectWalletDialog to populate info$ when connecting - Update NWCConnection type to include network field This eliminates unnecessary NWC get_info calls that were made every time WalletViewer or ZapWindow mounted. The info is now cached from initial connection and served from the observable.
This commit is contained in:
@@ -11,7 +11,7 @@ import {
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { useGrimoire } from "@/core/state";
|
||||
import { createWalletFromURI } from "@/services/nwc";
|
||||
import { createWalletFromURI, setWalletInfo } from "@/services/nwc";
|
||||
|
||||
interface ConnectWalletDialogProps {
|
||||
open: boolean;
|
||||
@@ -85,6 +85,7 @@ export default function ConnectWalletDialog({
|
||||
alias: info.alias,
|
||||
methods: info.methods,
|
||||
notifications: info.notifications,
|
||||
network: info.network,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -93,12 +94,15 @@ export default function ConnectWalletDialog({
|
||||
updateNWCBalance(balance);
|
||||
}
|
||||
|
||||
// Update info
|
||||
updateNWCInfo({
|
||||
// Update info in state and observable
|
||||
const cachedInfo = {
|
||||
alias: info.alias,
|
||||
methods: info.methods,
|
||||
notifications: info.notifications,
|
||||
});
|
||||
network: info.network,
|
||||
};
|
||||
updateNWCInfo(cachedInfo);
|
||||
setWalletInfo(cachedInfo);
|
||||
|
||||
// Show success toast
|
||||
toast.success("Wallet Connected");
|
||||
|
||||
@@ -76,17 +76,6 @@ interface Transaction {
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
interface WalletInfo {
|
||||
alias?: string;
|
||||
color?: string;
|
||||
pubkey?: string;
|
||||
network?: string;
|
||||
block_height?: number;
|
||||
block_hash?: string;
|
||||
methods: string[];
|
||||
notifications?: string[];
|
||||
}
|
||||
|
||||
interface InvoiceDetails {
|
||||
amount?: number;
|
||||
description?: string;
|
||||
@@ -408,8 +397,8 @@ export default function WalletViewer() {
|
||||
const {
|
||||
wallet,
|
||||
balance,
|
||||
info: walletInfo,
|
||||
isConnected,
|
||||
getInfo,
|
||||
refreshBalance,
|
||||
listTransactions,
|
||||
makeInvoice,
|
||||
@@ -417,8 +406,6 @@ export default function WalletViewer() {
|
||||
lookupInvoice,
|
||||
disconnect,
|
||||
} = useWallet();
|
||||
|
||||
const [walletInfo, setWalletInfo] = useState<WalletInfo | null>(null);
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loadingMore, setLoadingMore] = useState(false);
|
||||
@@ -429,7 +416,6 @@ export default function WalletViewer() {
|
||||
const [txLoadFailed, setTxLoadFailed] = useState(false);
|
||||
|
||||
// Use refs to track loading attempts without causing re-renders
|
||||
const walletInfoLoadedRef = useRef(false);
|
||||
const lastConnectionStateRef = useRef(isConnected);
|
||||
const lastBalanceRefreshRef = useRef(0);
|
||||
const lastTxLoadRef = useRef(0);
|
||||
@@ -462,43 +448,28 @@ export default function WalletViewer() {
|
||||
const [showRawTransaction, setShowRawTransaction] = useState(false);
|
||||
const [copiedRawTx, setCopiedRawTx] = useState(false);
|
||||
|
||||
// Load wallet info when connected
|
||||
// Reset state when connection changes
|
||||
useEffect(() => {
|
||||
// Detect connection state changes
|
||||
if (isConnected !== lastConnectionStateRef.current) {
|
||||
lastConnectionStateRef.current = isConnected;
|
||||
walletInfoLoadedRef.current = false;
|
||||
|
||||
if (isConnected) {
|
||||
// Reset transaction loading flags when wallet connects
|
||||
setTxLoadAttempted(false);
|
||||
setTxLoadFailed(false);
|
||||
setTransactions([]);
|
||||
setWalletInfo(null);
|
||||
} else {
|
||||
// Clear all state when wallet disconnects
|
||||
setTxLoadAttempted(false);
|
||||
setTxLoadFailed(false);
|
||||
setTransactions([]);
|
||||
setWalletInfo(null);
|
||||
setLoading(false);
|
||||
setLoadingMore(false);
|
||||
setHasMore(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Load wallet info if connected and not yet loaded
|
||||
if (isConnected && !walletInfoLoadedRef.current) {
|
||||
walletInfoLoadedRef.current = true;
|
||||
getInfo()
|
||||
.then((info) => setWalletInfo(info))
|
||||
.catch((error) => {
|
||||
console.error("Failed to load wallet info:", error);
|
||||
toast.error("Failed to load wallet info");
|
||||
walletInfoLoadedRef.current = false; // Allow retry
|
||||
});
|
||||
}
|
||||
}, [isConnected, getInfo]);
|
||||
}, [isConnected]);
|
||||
|
||||
// Load transactions when wallet info is available (only once)
|
||||
useEffect(() => {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* - Shows feed render of zapped event
|
||||
*/
|
||||
|
||||
import { useState, useMemo, useEffect, useRef } from "react";
|
||||
import { useState, useMemo, useRef } from "react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Zap,
|
||||
@@ -117,17 +117,7 @@ export function ZapWindow({
|
||||
const activeAccount = accountManager.active;
|
||||
const canSign = !!activeAccount?.signer;
|
||||
|
||||
const { wallet, payInvoice, refreshBalance, getInfo } = useWallet();
|
||||
|
||||
// Fetch wallet info
|
||||
const [walletInfo, setWalletInfo] = useState<any>(null);
|
||||
useEffect(() => {
|
||||
if (wallet) {
|
||||
getInfo()
|
||||
.then((info) => setWalletInfo(info))
|
||||
.catch((error) => console.error("Failed to get wallet info:", error));
|
||||
}
|
||||
}, [wallet, getInfo]);
|
||||
const { wallet, info: walletInfo, payInvoice, refreshBalance } = useWallet();
|
||||
|
||||
// Cache LNURL data for recipient's Lightning address
|
||||
const { data: lnurlData } = useLnurlCache(recipientProfile?.lud16);
|
||||
@@ -717,7 +707,10 @@ export function ZapWindow({
|
||||
isPaid
|
||||
? onClose?.()
|
||||
: handleZap(
|
||||
wallet && walletInfo?.methods.includes("pay_invoice"),
|
||||
!!(
|
||||
wallet &&
|
||||
walletInfo?.methods.includes("pay_invoice")
|
||||
),
|
||||
)
|
||||
}
|
||||
disabled={
|
||||
|
||||
@@ -29,6 +29,8 @@ import {
|
||||
clearWallet as clearWalletService,
|
||||
refreshBalance as refreshBalanceService,
|
||||
balance$,
|
||||
info$,
|
||||
type WalletInfo,
|
||||
} from "@/services/nwc";
|
||||
import type { WalletConnect } from "applesauce-wallet-connect";
|
||||
|
||||
@@ -40,6 +42,9 @@ export function useWallet() {
|
||||
// Subscribe to balance updates from observable (fully reactive!)
|
||||
const balance = use$(balance$);
|
||||
|
||||
// Subscribe to cached wallet info (from initial connection)
|
||||
const info = use$(info$);
|
||||
|
||||
// Initialize wallet on mount if connection exists but no wallet instance
|
||||
useEffect(() => {
|
||||
if (nwcConnection && !wallet) {
|
||||
@@ -175,13 +180,15 @@ export function useWallet() {
|
||||
wallet,
|
||||
/** Current balance in millisats (auto-updates via observable!) */
|
||||
balance,
|
||||
/** Cached wallet info (alias, methods, notifications) from initial connection */
|
||||
info,
|
||||
/** Whether a wallet is connected */
|
||||
isConnected: !!wallet,
|
||||
/** Pay a BOLT11 invoice */
|
||||
payInvoice,
|
||||
/** Generate a new invoice */
|
||||
makeInvoice,
|
||||
/** Get wallet information */
|
||||
/** Get wallet information (prefer using cached `info` instead) */
|
||||
getInfo,
|
||||
/** Get current balance */
|
||||
getBalance,
|
||||
@@ -197,3 +204,5 @@ export function useWallet() {
|
||||
disconnect,
|
||||
};
|
||||
}
|
||||
|
||||
export type { WalletInfo };
|
||||
|
||||
@@ -28,6 +28,23 @@ let notificationSubscription: Subscription | null = null;
|
||||
*/
|
||||
export const balance$ = new BehaviorSubject<number | undefined>(undefined);
|
||||
|
||||
/**
|
||||
* Cached wallet info type
|
||||
* Contains the essential fields from NIP-47 get_info response
|
||||
*/
|
||||
export type WalletInfo = {
|
||||
alias?: string;
|
||||
methods: string[];
|
||||
notifications?: string[];
|
||||
network?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Observable for wallet info
|
||||
* Cached from initial connection, components can subscribe via use$()
|
||||
*/
|
||||
export const info$ = new BehaviorSubject<WalletInfo | undefined>(undefined);
|
||||
|
||||
/**
|
||||
* Helper to convert hex string to Uint8Array
|
||||
*/
|
||||
@@ -107,6 +124,11 @@ export function restoreWallet(connection: NWCConnection): WalletConnect {
|
||||
balance$.next(connection.balance);
|
||||
}
|
||||
|
||||
// Set cached info from connection
|
||||
if (connection.info) {
|
||||
info$.next(connection.info);
|
||||
}
|
||||
|
||||
subscribeToNotifications(walletInstance);
|
||||
return walletInstance;
|
||||
}
|
||||
@@ -128,6 +150,15 @@ export function clearWallet(): void {
|
||||
}
|
||||
walletInstance = null;
|
||||
balance$.next(undefined);
|
||||
info$.next(undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cached wallet info
|
||||
* Called after initial connection to cache the get_info response
|
||||
*/
|
||||
export function setWalletInfo(info: WalletInfo): void {
|
||||
info$.next(info);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,8 +98,9 @@ export interface NWCConnection {
|
||||
/** Optional wallet info */
|
||||
info?: {
|
||||
alias?: string;
|
||||
methods?: string[];
|
||||
methods: string[];
|
||||
notifications?: string[];
|
||||
network?: string;
|
||||
};
|
||||
/** Last connection time */
|
||||
lastConnected?: number;
|
||||
|
||||
Reference in New Issue
Block a user