import { useState, useCallback } from 'react'; import { isUnknownMintError, extractMintUrlFromError } from './useMintManager'; import type { Manager } from 'coco-cashu-core'; import type { Token } from '@cashu/cashu-ts'; import { useToast } from '@/hooks/useToast'; interface UseTokenOperationsProps { coco: Manager | null; activeMintUrl: string | null; generateQRCode: (text: string) => Promise; getEncodedToken: (token: Token | string) => string; } export function useTokenOperations({ coco, activeMintUrl, generateQRCode, getEncodedToken, }: UseTokenOperationsProps) { const { toast } = useToast(); // Receive state const [tokenInput, setTokenInput] = useState(''); // Send state const [sendAmount, setSendAmount] = useState(''); // Transaction output state const [sentToken, setSentToken] = useState(null); const [sentTokenQRCode, setSentTokenQRCode] = useState(''); // Generate QR code for sent token const generateSentTokenQRCode = useCallback(async (token: string) => { try { const qrCodeUrl = await generateQRCode(token); setSentTokenQRCode(qrCodeUrl); } catch (err) { console.error('[Cashu] Failed to generate sent token QR code:', err); } }, [generateQRCode]); // Handle unknown mint error by adding the mint and retrying const handleUnknownMintError = useCallback( async (mintUrl: string) => { if (!coco) return; try { console.log('[Cashu] Adding unknown mint:', mintUrl); // Check if mint exists const allMints = await coco.mint.getAllMints(); const isKnown = allMints.some(m => m.mintUrl.toLowerCase() === mintUrl.toLowerCase()); if (isKnown) { // Mint exists but may not be trusted const isTrusted = await coco.mint.isTrustedMint(mintUrl); if (!isTrusted) { await coco.mint.trustMint(mintUrl); } } else { // Add the mint and automatically trust it await coco.mint.addMint(mintUrl, { trusted: true }); } // Retry receiving the token await coco.wallet.receive(tokenInput); setTokenInput(''); toast({ title: 'Token received', description: `Token redeemed successfully! Added new mint: ${new URL(mintUrl).host}` }); } catch (retryErr) { toast({ variant: 'destructive', title: 'Receive failed', description: retryErr instanceof Error ? retryErr.message : 'Unknown error' }); } }, [coco, tokenInput, toast] ); // Handle receive (token) const handleTokenReceive = useCallback(async () => { if (!coco || !tokenInput) return; try { const tokenToProcess = tokenInput.trim(); console.log('[Cashu] Attempting to receive token:', tokenToProcess.substring(0, 20) + '...'); await coco.wallet.receive(tokenToProcess); setTokenInput(''); toast({ title: 'Token received', description: 'Cashu token redeemed successfully!' }); } catch (err) { console.error('[Cashu] Token receive error:', err); // Handle UnknownMintError by automatically adding the mint if (isUnknownMintError(err)) { const mintUrl = extractMintUrlFromError(err); if (mintUrl) { await handleUnknownMintError(mintUrl); return; } } toast({ variant: 'destructive', title: 'Receive failed', description: err instanceof Error ? err.message : 'Unknown error' }); } }, [coco, tokenInput, handleUnknownMintError, toast]); // Handle send (token) const handleTokenSend = useCallback(async () => { if (!coco || !sendAmount || !activeMintUrl) return; try { const amount = parseInt(sendAmount); if (isNaN(amount) || amount <= 0) { toast({ variant: 'destructive', title: 'Invalid amount', description: 'Please enter a valid amount' }); return; } const token = await coco.wallet.send(activeMintUrl, amount); const encodedToken = getEncodedToken(token); setSentToken(encodedToken); await generateSentTokenQRCode(encodedToken); setSendAmount(''); toast({ title: 'Token created', description: `${amount} sats token ready to share` }); } catch (err) { toast({ variant: 'destructive', title: 'Send failed', description: err instanceof Error ? err.message : 'Unknown error' }); } }, [coco, sendAmount, activeMintUrl, getEncodedToken, generateSentTokenQRCode, toast]); return { // Receive state tokenInput, setTokenInput, handleTokenReceive, // Send state sendAmount, setSendAmount, handleTokenSend, // Transaction output state sentToken, setSentToken, sentTokenQRCode, }; }