import {
AlertTriangleIcon,
ExternalLinkIcon,
InfoIcon,
PencilIcon,
XIcon,
} from "lucide-react";
import React from "react";
import { Link, useLocation, useNavigate } from "react-router";
import { toast } from "sonner";
import { AnchorReserveAlert } from "src/components/AnchorReserveAlert";
import AppHeader from "src/components/AppHeader";
import { CurrencyInputField } from "src/components/CurrencyInputField";
import ExternalLink from "src/components/ExternalLink";
import { InsufficientLightningBalanceAlert } from "src/components/InsufficientLightningBalanceAlert";
import Loading from "src/components/Loading";
import { MempoolAlert } from "src/components/MempoolAlert";
import { Alert, AlertDescription, AlertTitle } from "src/components/ui/alert";
import { Button } from "src/components/ui/button";
import { LinkButton } from "src/components/ui/custom/link-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 { Switch } from "src/components/ui/switch";
import { ONCHAIN_DUST_SATS } from "src/constants";
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 {
InitiateSwapRequest,
RedeemOnchainFundsRequest,
RedeemOnchainFundsResponse,
SwapResponse,
} from "src/types";
import { request } from "src/utils/request";
export default function Onchain() {
const { state } = useLocation();
const navigate = useNavigate();
const [isSwap, setSwap] = React.useState(false);
const address = state?.args?.address as string;
const initialAmountSat = (state?.args?.amountSat as string | undefined) ?? "";
const [amountSat, setAmountSat] = React.useState(initialAmountSat);
React.useEffect(() => {
if (!address) {
navigate("/wallet/send");
}
}, [navigate, address]);
if (!address) {
return ;
}
return (
Recipient
{address.match(/.{1,4}/g)?.map((word, index) => {
if (index % 2 === 0) {
return (
{word}
);
} else {
return (
{word}
);
}
})}
{isSwap ? (
) : (
)}
);
}
function OnchainForm({
address,
setSwap,
amountSat,
setAmountSat,
}: {
address: string;
amountSat: string;
setAmountSat: React.Dispatch>;
setSwap: React.Dispatch>;
}) {
const navigate = useNavigate();
const { data: info } = useInfo();
const { data: balances } = useBalances();
const { data: recommendedFees, error: mempoolError } = useMempoolApi<{
fastestFee: number;
halfHourFee: number;
economyFee: number;
minimumFee: number;
}>("/v1/fees/recommended");
const [feeRate, setFeeRate] = React.useState("");
const [isLoading, setLoading] = React.useState(false);
const [editFee, setEditFee] = React.useState(false);
React.useEffect(() => {
if (recommendedFees?.fastestFee) {
setFeeRate(recommendedFees.fastestFee.toString());
}
}, [recommendedFees]);
const onSubmit = async (event: React.FormEvent) => {
event.preventDefault();
try {
if (!balances) {
return;
}
if (balances.onchain.spendableSat <= ONCHAIN_DUST_SATS) {
throw new Error(
"You currently don't have enough sats to pay for an on-chain transaction. Consider swapping from Lightning Balance."
);
}
setLoading(true);
const payload: RedeemOnchainFundsRequest = {
toAddress: address,
amountSat: +amountSat,
feeRate: +feeRate,
};
const response = await request(
"/api/wallet/redeem-onchain-funds",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
}
);
if (!response?.txId) {
throw new Error("No address in response");
}
navigate(`/wallet/send/onchain-success`, {
state: {
amountSat: +amountSat,
txId: response.txId,
},
replace: true,
});
toast("Successfully broadcasted transaction");
} catch (e) {
toast.error("Failed to send payment", {
description: "" + e,
});
console.error(e);
} finally {
setLoading(false);
}
};
if (!info || !balances || (!recommendedFees && !mempoolError)) {
return ;
}
return (
);
}
function SwapForm({
address,
setSwap,
amountSat,
setAmountSat,
}: {
address: string;
amountSat: string;
setAmountSat: React.Dispatch>;
setSwap: React.Dispatch>;
}) {
const navigate = useNavigate();
const { data: balances } = useBalances();
const { data: swapInfo } = useSwapInfo("out");
const [isLoading, setLoading] = React.useState(false);
const onSubmit = async (event: React.FormEvent) => {
event.preventDefault();
try {
setLoading(true);
const payload: InitiateSwapRequest = {
swapAmountSat: +amountSat,
destination: address,
};
const swapOutResponse = await request("/api/swaps/out", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (!swapOutResponse) {
throw new Error("Error swapping out");
}
navigate(`/wallet/swap/out/status/${swapOutResponse.swapId}`);
toast("Initiated swap");
} catch (e) {
console.error(e);
toast.error("Failed to send payment", {
description: "" + e,
});
} finally {
setLoading(false);
}
};
const { data: recommendedFees } = useMempoolApi<{
fastestFee: number;
}>("/v1/fees/recommended");
if (!balances || !swapInfo) {
return ;
}
return (
);
}