import { Invoice } from "@getalby/lightning-tools/bolt11"; import { LightningAddress } from "@getalby/lightning-tools/lnurl"; import { validate as validateBitcoinAddress } from "bitcoin-address-validation"; import { ClipboardPasteIcon } from "lucide-react"; import React from "react"; import { useNavigate, useSearchParams } from "react-router"; import { toast } from "sonner"; import AppHeader from "src/components/AppHeader"; import { CryptoSwapAlert } from "src/components/CryptoSwapAlert"; import Loading from "src/components/Loading"; import { Button } from "src/components/ui/button"; import { LoadingButton } from "src/components/ui/custom/loading-button"; import { Input } from "src/components/ui/input"; import { Label } from "src/components/ui/label"; import { useBalances } from "src/hooks/useBalances"; import { useChannels } from "src/hooks/useChannels"; import { parseBip21 } from "src/utils/parseBip21"; export default function Send() { const { data: balances } = useBalances(); const { data: channels } = useChannels(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const [recipient, setRecipient] = React.useState(""); const [isLoading, setLoading] = React.useState(false); const [showSwapAlert, setShowSwapAlert] = React.useState(false); const handleBip21 = React.useCallback( (uri: string) => { const bip21 = parseBip21(uri); if (bip21.lightning) { const invoice = new Invoice({ pr: bip21.lightning }); if (invoice.satoshi === 0) { navigate(`/wallet/send/0-amount`, { state: { args: { paymentRequest: invoice } }, }); } else { navigate(`/wallet/send/confirm-payment`, { state: { args: { paymentRequest: invoice } }, }); } return; } if (!bip21.address || !validateBitcoinAddress(bip21.address)) { throw new Error("invalid bitcoin address"); } navigate(`/wallet/send/onchain`, { state: { args: { address: bip21.address, amountSat: bip21.amountSat ? String(bip21.amountSat) : undefined, }, }, }); }, [navigate] ); React.useEffect(() => { const uri = searchParams.get("bip21"); if (!uri) { return; } try { handleBip21(uri); } catch (error) { toast.error("Invalid Bitcoin URI", { description: "" + error }); } }, [searchParams, handleBip21]); const paste = async () => { const text = await navigator.clipboard.readText(); setRecipient(text.trim()); }; const onSubmit = async (event: React.FormEvent) => { event.preventDefault(); try { setLoading(true); if (/^bitcoin:/i.test(recipient)) { handleBip21(recipient); return; } if (validateBitcoinAddress(recipient)) { navigate(`/wallet/send/onchain`, { state: { args: { address: recipient }, }, }); return; } if (recipient.includes("@")) { const lnAddress = new LightningAddress(recipient); await lnAddress.fetch(); if (lnAddress.lnurlpData) { navigate(`/wallet/send/lnurl-pay`, { state: { args: { lnAddress }, }, }); return; } } const invoice = new Invoice({ pr: recipient }); if (invoice.satoshi === 0) { navigate(`/wallet/send/0-amount`, { state: { args: { paymentRequest: invoice }, }, }); return; } navigate(`/wallet/send/confirm-payment`, { state: { args: { paymentRequest: invoice }, }, }); } catch (error) { setShowSwapAlert(true); toast.error("Invalid recipient", { description: "" + error, }); console.error(error); } finally { setLoading(false); } }; if (!balances || !channels) { return ; } return (
{showSwapAlert && }
{ setRecipient(e.target.value.trim()); setShowSwapAlert(false); }} />
Continue
); }