import { useEffect, useState } from "react"; import { useNavigate } from "react-router"; import { toast } from "sonner"; import AppHeader from "src/components/AppHeader"; import { CurrencyInputField } from "src/components/CurrencyInputField"; import { FixedFloatSwapInFlow } from "src/components/FixedFloatSwapInFlow"; import Loading from "src/components/Loading"; import LowReceivingCapacityAlert from "src/components/LowReceivingCapacityAlert"; import { MempoolAlert } from "src/components/MempoolAlert"; import { LoadingButton } from "src/components/ui/custom/loading-button"; import { Label } from "src/components/ui/label"; import { RadioGroup, RadioGroupItem } from "src/components/ui/radio-group"; import { useBalances } from "src/hooks/useBalances"; import { useInfo } from "src/hooks/useInfo"; import { useMempoolApi } from "src/hooks/useMempoolApi"; import { useSwapInfo } from "src/hooks/useSwaps"; import { CreateInvoiceRequest, InitiateSwapRequest, SwapResponse, Transaction, } from "src/types"; import { openLink } from "src/utils/openLink"; import { request } from "src/utils/request"; export default function ReceiveOnchain() { const { data: info, hasChannelManagement } = useInfo(); const { data: balances } = useBalances(); const { data: swapInfo } = useSwapInfo("in"); const { data: recommendedFees, error: mempoolError } = useMempoolApi<{ fastestFee: number; halfHourFee: number; economyFee: number; minimumFee: number; }>("/v1/fees/recommended"); const navigate = useNavigate(); const [swapFrom, setSwapFrom] = useState<"bitcoin" | "crypto">("bitcoin"); const [swapAmountSat, setSwapAmountSat] = useState(""); const [loading, setLoading] = useState(false); const [feeRate, setFeeRate] = useState(""); const [cryptoTransaction, setCryptoTransaction] = useState(null); useEffect(() => { if (recommendedFees?.fastestFee) { setFeeRate(recommendedFees.fastestFee.toString()); } }, [recommendedFees]); const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { setLoading(true); if (swapFrom === "crypto") { const tx = await request("/api/invoices", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ amountMsat: (parseInt(swapAmountSat) || 0) * 1000, description: "Fixed Float swap", } as CreateInvoiceRequest), }); if (!tx?.invoice) { throw new Error("Failed to create invoice"); } setCryptoTransaction(tx); openLink( `https://ff.io/?to=BTCLN&address=${encodeURIComponent(tx.invoice)}&ref=qnnjvywb` ); toast("Initiated swap"); return; } const payload: InitiateSwapRequest = { swapAmountSat: parseInt(swapAmountSat), }; const swapInResponse = await request("/api/swaps/in", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(payload), }); if (!swapInResponse) { throw new Error("Error swapping in"); } navigate(`/wallet/swap/in/status/${swapInResponse.swapId}`, { replace: true, }); toast("Initiated swap"); } catch (error) { toast.error("Failed to initiate swap", { description: (error as Error).message, }); } finally { setLoading(false); } }; if (!info || !balances || !swapInfo || (!recommendedFees && !mempoolError)) { return ; } const isCryptoReceiveState = swapFrom === "crypto" && cryptoTransaction !== null; return (
{!isCryptoReceiveState && ( <> {hasChannelManagement && parseInt(swapAmountSat || "0") * 1000 >= 0.8 * balances.lightning.totalReceivableMsat && ( )}
{ setSwapFrom(value as "bitcoin" | "crypto"); }} className="flex gap-4 flex-row" >
)} {swapFrom === "bitcoin" ? ( ) : ( { setCryptoTransaction(null); setSwapAmountSat(""); }} /> )}
); } function BitcoinSwapFlow({ feeRate, loading, swapFee, }: { feeRate: string; loading: boolean; swapFee: number; }) { return ( <>
{feeRate ? (

{feeRate} sat/vB

) : ( )}

{swapFee}%

Continue ); }