import { useState } from 'react'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { useCashuEscrow } from '@/hooks/wallet/useCashuEscrow'; import { useTradeAttestationRequest } from '@/hooks/useTradeAttestations'; import { useToast } from '@/hooks/useToast'; import { ESCROW_DEFAULT_LOCK_DAYS, ESCROW_MIN_LOCK_DAYS } from '@/lib/cashuEscrow'; import { Loader2, Lock } from 'lucide-react'; /** * Buyer: lock funds in Cashu escrow (P2PK to the seller, refundable after a * deadline) and send the `31872` confirmation request carrying the token. * * Native-only (the Cashu wallet is Capacitor-gated). EXPERIMENTAL — the * mint-touching path has not been verified on a device; start with small * amounts. */ export function EscrowRequestDialog({ open, onOpenChange, listing, sellerPubkey, sellerName, }: { open: boolean; onOpenChange: (open: boolean) => void; listing: { pubkey: string; identifier: string }; sellerPubkey: string; sellerName: string; }) { const escrow = useCashuEscrow(); const { publishRequest, isPending: publishing } = useTradeAttestationRequest(); const { toast } = useToast(); const [amount, setAmount] = useState(''); const [days, setDays] = useState(String(ESCROW_DEFAULT_LOCK_DAYS)); const [busy, setBusy] = useState(false); const submit = async () => { const amountSats = parseInt(amount, 10); const lockDays = parseInt(days, 10); if (!Number.isFinite(amountSats) || amountSats <= 0) { toast({ title: 'Enter an escrow amount', variant: 'destructive' }); return; } if (!Number.isFinite(lockDays) || lockDays < ESCROW_MIN_LOCK_DAYS) { toast({ title: `Lock for at least ${ESCROW_MIN_LOCK_DAYS} day`, variant: 'destructive' }); return; } setBusy(true); try { const { token } = await escrow.createEscrow({ amountSats, sellerPubkey, lockDays }); await publishRequest({ listing, attestor: sellerPubkey, cashuToken: token, note: `Escrowed ${amountSats} sats for our trade — please confirm the sale.`, }); toast({ title: 'Escrow created 🎉', description: `${amountSats} sats locked for ${lockDays} days. ${sellerName} can redeem on delivery.`, }); onOpenChange(false); } catch (e) { toast({ title: 'Could not create escrow', description: e instanceof Error ? e.message : 'Something went wrong.', variant: 'destructive', }); } finally { setBusy(false); } }; const pending = busy || publishing; return ( Escrow this trade Funds are locked to {sellerName} and refundable by you if the deal falls through after the deadline. Requires a connected Lightning wallet.
setAmount(e.target.value)} inputMode="numeric" placeholder="e.g. 45000" className="h-11 border-gray-700 bg-gray-900 text-white" />
setDays(e.target.value)} inputMode="numeric" className="h-11 border-gray-700 bg-gray-900 text-white" />

After this many days you can reclaim the funds if the seller hasn't delivered.

{!escrow.available && (

Cashu escrow is available in the SkateSpots app only (not the web build).

)}
); }