mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2026-01-16 20:54:20 +01:00
fedi swap edit and "stages"
This commit is contained in:
committed by
Tony Giorgio
parent
570e46dbff
commit
e753fa34fb
@@ -1,53 +1,8 @@
|
||||
import { MutinyInvoice } from "@mutinywallet/mutiny-wasm";
|
||||
import { A, useNavigate, useSearchParams } from "@solidjs/router";
|
||||
import {
|
||||
createEffect,
|
||||
createMemo,
|
||||
createResource,
|
||||
createSignal,
|
||||
JSX,
|
||||
Match,
|
||||
onMount,
|
||||
Show,
|
||||
Suspense,
|
||||
Switch
|
||||
} from "solid-js";
|
||||
import { A } from "@solidjs/router";
|
||||
import { Match, Switch } from "solid-js";
|
||||
|
||||
import bolt from "~/assets/icons/bolt.svg";
|
||||
import chain from "~/assets/icons/chain.svg";
|
||||
import close from "~/assets/icons/close.svg";
|
||||
import {
|
||||
ActivityDetailsModal,
|
||||
AmountEditable,
|
||||
AmountFiat,
|
||||
AmountSats,
|
||||
BackPop,
|
||||
Button,
|
||||
DefaultMain,
|
||||
Fee,
|
||||
FeeDisplay,
|
||||
HackActivityType,
|
||||
InfoBox,
|
||||
LabelCircle,
|
||||
LoadingShimmer,
|
||||
MegaCheck,
|
||||
MegaClock,
|
||||
MegaEx,
|
||||
MethodChoice,
|
||||
MutinyWalletGuard,
|
||||
NavBar,
|
||||
showToast,
|
||||
SimpleInput,
|
||||
SmallHeader,
|
||||
StringShower,
|
||||
SuccessModal,
|
||||
UnstyledBackPop,
|
||||
VStack
|
||||
} from "~/components";
|
||||
import { InfoBox, MegaClock, MegaEx } from "~/components";
|
||||
import { useI18n } from "~/i18n/context";
|
||||
import { ParsedParams } from "~/logic/waila";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { eify, vibrateSuccess } from "~/utils";
|
||||
|
||||
export function Failure(props: { reason: string }) {
|
||||
const i18n = useI18n();
|
||||
|
||||
@@ -603,7 +603,10 @@ export default {
|
||||
swap_lightning: {
|
||||
insufficient_funds: "You don't have enough funds to swap to lightning",
|
||||
header: "Swap to Lightning",
|
||||
header_preview: "Preview Swap",
|
||||
completed: "Swap Completed",
|
||||
too_small:
|
||||
"Invalid amount entered. You need to swap at least 100k sats.",
|
||||
sats_added: "+{{amount}} sats have been added to your Lightning balance",
|
||||
sats_fee: "+{{amount}} sats fee",
|
||||
confirm_swap: "Confirm Swap",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MutinyInvoice, TagItem } from "@mutinywallet/mutiny-wasm";
|
||||
import { A, useNavigate, useSearchParams } from "@solidjs/router";
|
||||
import { useNavigate, useSearchParams } from "@solidjs/router";
|
||||
import {
|
||||
createEffect,
|
||||
createMemo,
|
||||
@@ -33,8 +33,6 @@ import {
|
||||
LabelCircle,
|
||||
LoadingShimmer,
|
||||
MegaCheck,
|
||||
MegaClock,
|
||||
MegaEx,
|
||||
MethodChoice,
|
||||
MutinyWalletGuard,
|
||||
NavBar,
|
||||
@@ -236,8 +234,8 @@ export function Send() {
|
||||
? sentDetails()?.txid
|
||||
: undefined
|
||||
: sentDetails()
|
||||
? sentDetails()?.payment_hash
|
||||
: undefined;
|
||||
? sentDetails()?.payment_hash
|
||||
: undefined;
|
||||
const kind = sentDetails()?.txid ? "OnChain" : "Lightning";
|
||||
|
||||
console.log("Opening details modal: ", paymentTxId, kind);
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
import { createForm, required } from "@modular-forms/solid";
|
||||
import { FedimintSweepResult } from "@mutinywallet/mutiny-wasm";
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import {
|
||||
createMemo,
|
||||
createResource,
|
||||
createSignal,
|
||||
For,
|
||||
Match,
|
||||
Show,
|
||||
Switch
|
||||
} from "solid-js";
|
||||
import { createMemo, createSignal, Match, Show, Switch } from "solid-js";
|
||||
|
||||
import {
|
||||
ActivityDetailsModal,
|
||||
AmountEditable,
|
||||
AmountFiat,
|
||||
BackButton,
|
||||
BackLink,
|
||||
Button,
|
||||
Card,
|
||||
DefaultMain,
|
||||
Failure,
|
||||
Fee,
|
||||
@@ -25,17 +15,13 @@ import {
|
||||
InfoBox,
|
||||
LargeHeader,
|
||||
MegaCheck,
|
||||
MegaEx,
|
||||
MutinyWalletGuard,
|
||||
NavBar,
|
||||
ReceiveWarnings,
|
||||
showToast,
|
||||
SuccessModal,
|
||||
TextField,
|
||||
VStack
|
||||
} from "~/components";
|
||||
import { useI18n } from "~/i18n/context";
|
||||
import { Network } from "~/logic/mutinyWalletSetup";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { eify, vibrateSuccess } from "~/utils";
|
||||
|
||||
@@ -49,11 +35,14 @@ export function SwapLightning() {
|
||||
const navigate = useNavigate();
|
||||
const i18n = useI18n();
|
||||
|
||||
const [stage, setStage] = createSignal<"start" | "preview" | "done">(
|
||||
"start"
|
||||
);
|
||||
|
||||
const [amountSats, setAmountSats] = createSignal(0n);
|
||||
const [feeSats, setFeeSats] = createSignal(0n);
|
||||
const [maxFederationBalanceBeforeSwap, setMaxFederationBalanceBeforeSwap] =
|
||||
createSignal(0n);
|
||||
const [previewFee, setPreviewFee] = createSignal(false);
|
||||
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
|
||||
@@ -62,49 +51,46 @@ export function SwapLightning() {
|
||||
function resetState() {
|
||||
setAmountSats(0n);
|
||||
setFeeSats(0n);
|
||||
setPreviewFee(false);
|
||||
setMaxFederationBalanceBeforeSwap(0n);
|
||||
setLoading(false);
|
||||
setSweepResult(undefined);
|
||||
setStage("start");
|
||||
}
|
||||
|
||||
const handleSwap = async () => {
|
||||
if (canSwap()) {
|
||||
try {
|
||||
setLoading(true);
|
||||
try {
|
||||
setLoading(true);
|
||||
setFeeEstimateWarning(undefined);
|
||||
|
||||
if (isMax()) {
|
||||
const result =
|
||||
await state.mutiny_wallet?.sweep_federation_balance(
|
||||
undefined
|
||||
);
|
||||
if (isMax()) {
|
||||
const result =
|
||||
await state.mutiny_wallet?.sweep_federation_balance(
|
||||
undefined
|
||||
);
|
||||
|
||||
setSweepResult({ result: result });
|
||||
} else {
|
||||
const result =
|
||||
await state.mutiny_wallet?.sweep_federation_balance(
|
||||
amountSats()
|
||||
);
|
||||
setSweepResult({ result: result });
|
||||
} else {
|
||||
const result =
|
||||
await state.mutiny_wallet?.sweep_federation_balance(
|
||||
amountSats()
|
||||
);
|
||||
|
||||
setSweepResult({ result: result });
|
||||
}
|
||||
|
||||
await vibrateSuccess();
|
||||
} catch (e) {
|
||||
const error = eify(e);
|
||||
setSweepResult({ failure_reason: error.message });
|
||||
console.error(e);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setSweepResult({ result: result });
|
||||
}
|
||||
|
||||
await vibrateSuccess();
|
||||
} catch (e) {
|
||||
const error = eify(e);
|
||||
setSweepResult({ failure_reason: error.message });
|
||||
console.error(e);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const canSwap = () => {
|
||||
const balance = state.balance?.federation || 0n;
|
||||
const network = state.mutiny_wallet?.get_network() as Network;
|
||||
|
||||
return amountSats() <= balance;
|
||||
return amountSats() > 0n && amountSats() <= balance;
|
||||
};
|
||||
|
||||
const amountWarning = () => {
|
||||
@@ -135,43 +121,53 @@ export function SwapLightning() {
|
||||
return feeSats() !== 0n;
|
||||
});
|
||||
|
||||
const feeEstimate = async () => {
|
||||
if (canSwap()) {
|
||||
try {
|
||||
setLoading(true);
|
||||
if (isMax()) {
|
||||
const fee =
|
||||
await state.mutiny_wallet?.estimate_sweep_federation_fee(
|
||||
undefined
|
||||
);
|
||||
setFeeSats(fee);
|
||||
setMaxFederationBalanceBeforeSwap(calculateMaxFederation());
|
||||
setPreviewFee(true);
|
||||
} else {
|
||||
const fee =
|
||||
await state.mutiny_wallet?.estimate_sweep_federation_fee(
|
||||
amountSats()
|
||||
);
|
||||
setFeeSats(fee);
|
||||
setMaxFederationBalanceBeforeSwap(calculateMaxFederation());
|
||||
setPreviewFee(true);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return undefined;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
const [feeEstimateWarning, setFeeEstimateWarning] = createSignal<string>();
|
||||
|
||||
return undefined;
|
||||
const feeEstimate = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setFeeEstimateWarning(undefined);
|
||||
|
||||
const fee =
|
||||
await state.mutiny_wallet?.estimate_sweep_federation_fee(
|
||||
isMax() ? undefined : amountSats()
|
||||
);
|
||||
|
||||
if (fee) {
|
||||
setFeeSats(fee);
|
||||
}
|
||||
setMaxFederationBalanceBeforeSwap(calculateMaxFederation());
|
||||
|
||||
setStage("preview");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
setFeeEstimateWarning(i18n.t("swap_lightning.too_small"));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<MutinyWalletGuard>
|
||||
<DefaultMain>
|
||||
<BackLink />
|
||||
<LargeHeader>{i18n.t("swap_lightning.header")}</LargeHeader>
|
||||
<Switch>
|
||||
<Match when={stage() === "start"}>
|
||||
<BackLink />
|
||||
<LargeHeader>
|
||||
{i18n.t("swap_lightning.header")}
|
||||
</LargeHeader>
|
||||
</Match>
|
||||
<Match when={stage() === "preview"}>
|
||||
<BackButton
|
||||
title={i18n.t("receive.edit")}
|
||||
onClick={() => setStage("start")}
|
||||
showOnDesktop
|
||||
/>
|
||||
<LargeHeader>
|
||||
{i18n.t("swap_lightning.header_preview")}
|
||||
</LargeHeader>
|
||||
</Match>
|
||||
</Switch>
|
||||
<SuccessModal
|
||||
confirmText={
|
||||
sweepResult()?.result
|
||||
@@ -189,7 +185,7 @@ export function SwapLightning() {
|
||||
>
|
||||
<Switch>
|
||||
<Match when={sweepResult()?.failure_reason}>
|
||||
<Failure reason={sweepResult()?.failure_reason} />
|
||||
<Failure reason={sweepResult()!.failure_reason!} />
|
||||
</Match>
|
||||
<Match when={sweepResult()?.result}>
|
||||
<MegaCheck />
|
||||
@@ -221,55 +217,101 @@ export function SwapLightning() {
|
||||
</SuccessModal>
|
||||
<div class="flex flex-1 flex-col justify-between gap-2">
|
||||
<div class="flex-1" />
|
||||
<VStack biggap>
|
||||
<AmountEditable
|
||||
initialAmountSats={amountSats()}
|
||||
setAmountSats={setAmountSats}
|
||||
activeMethod={{
|
||||
method: "lightning",
|
||||
maxAmountSats: maxFederationBalance()
|
||||
}}
|
||||
methods={[
|
||||
{
|
||||
method: "lightning",
|
||||
maxAmountSats: maxFederationBalance()
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<Show when={feeIsSet()}>
|
||||
<FeeDisplay
|
||||
amountSats={amountSats().toString()}
|
||||
fee={feeSats()!.toString()}
|
||||
maxAmountSats={maxFederationBalanceBeforeSwap()!.toString()}
|
||||
/>
|
||||
</Show>
|
||||
<ReceiveWarnings
|
||||
amountSats={amountSats() || "0"}
|
||||
from_fedi_to_ln={true}
|
||||
/>
|
||||
<Show when={amountWarning() && amountSats() > 0n}>
|
||||
<InfoBox accent={"red"}>{amountWarning()}</InfoBox>
|
||||
</Show>
|
||||
</VStack>
|
||||
<div class="flex-1" />
|
||||
<VStack>
|
||||
<Button
|
||||
disabled={!canSwap()}
|
||||
intent="blue"
|
||||
onClick={() => {
|
||||
if (!previewFee()) {
|
||||
feeEstimate();
|
||||
} else {
|
||||
handleSwap();
|
||||
}
|
||||
}}
|
||||
loading={loading()}
|
||||
>
|
||||
{!previewFee()
|
||||
? i18n.t("swap_lightning.preview_swap")
|
||||
: i18n.t("swap_lightning.confirm_swap")}
|
||||
</Button>
|
||||
</VStack>
|
||||
<Switch>
|
||||
<Match when={stage() === "start"}>
|
||||
<VStack biggap>
|
||||
<AmountEditable
|
||||
initialAmountSats={amountSats()}
|
||||
setAmountSats={setAmountSats}
|
||||
activeMethod={{
|
||||
method: "lightning",
|
||||
maxAmountSats: maxFederationBalance()
|
||||
}}
|
||||
methods={[
|
||||
{
|
||||
method: "lightning",
|
||||
maxAmountSats:
|
||||
maxFederationBalance()
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<ReceiveWarnings
|
||||
amountSats={amountSats() || "0"}
|
||||
from_fedi_to_ln={true}
|
||||
/>
|
||||
<Show
|
||||
when={amountWarning() && amountSats() > 0n}
|
||||
>
|
||||
<InfoBox accent={"red"}>
|
||||
{amountWarning()}
|
||||
</InfoBox>
|
||||
</Show>
|
||||
<Show when={feeEstimateWarning()}>
|
||||
<InfoBox accent={"red"}>
|
||||
{feeEstimateWarning()}
|
||||
</InfoBox>
|
||||
</Show>
|
||||
</VStack>
|
||||
<div class="flex-1" />
|
||||
<VStack>
|
||||
<Button
|
||||
disabled={!canSwap()}
|
||||
intent="blue"
|
||||
onClick={feeEstimate}
|
||||
loading={loading()}
|
||||
>
|
||||
{i18n.t("swap_lightning.preview_swap")}
|
||||
</Button>
|
||||
</VStack>
|
||||
</Match>
|
||||
<Match when={stage() === "preview"}>
|
||||
<VStack biggap>
|
||||
<AmountEditable
|
||||
frozenAmount
|
||||
initialAmountSats={amountSats()}
|
||||
setAmountSats={setAmountSats}
|
||||
activeMethod={{
|
||||
method: "lightning",
|
||||
maxAmountSats: maxFederationBalance()
|
||||
}}
|
||||
methods={[
|
||||
{
|
||||
method: "lightning",
|
||||
maxAmountSats:
|
||||
maxFederationBalance()
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<Show when={feeIsSet()}>
|
||||
<FeeDisplay
|
||||
amountSats={amountSats().toString()}
|
||||
fee={feeSats()!.toString()}
|
||||
maxAmountSats={
|
||||
maxFederationBalanceBeforeSwap()!
|
||||
}
|
||||
/>
|
||||
</Show>
|
||||
<Show
|
||||
when={amountWarning() && amountSats() > 0n}
|
||||
>
|
||||
<InfoBox accent={"red"}>
|
||||
{amountWarning()}
|
||||
</InfoBox>
|
||||
</Show>
|
||||
</VStack>
|
||||
<div class="flex-1" />
|
||||
<VStack>
|
||||
<Button
|
||||
disabled={!canSwap()}
|
||||
intent="blue"
|
||||
onClick={handleSwap}
|
||||
loading={loading()}
|
||||
>
|
||||
{i18n.t("swap_lightning.confirm_swap")}
|
||||
</Button>
|
||||
</VStack>
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="none" />
|
||||
|
||||
Reference in New Issue
Block a user