Skip to content

Commit

Permalink
Optional node manager
Browse files Browse the repository at this point in the history
  • Loading branch information
benthecarman committed Apr 22, 2024
1 parent 44b86e6 commit 8d1b9ff
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 69 deletions.
214 changes: 150 additions & 64 deletions src/components/BalanceBox.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { useNavigate } from "@solidjs/router";
import { Users } from "lucide-solid";
import { Match, Show, Switch } from "solid-js";
import { Plus, Trash, Users } from "lucide-solid";
import {
createResource,
createSignal,
Match,
Show,
Suspense,
Switch
} from "solid-js";

import {
AmountFiat,
Expand All @@ -11,6 +18,7 @@ import {
InfoBox,
MediumHeader,
NiceP,
SubtleButton,
VStack
} from "~/components";
import { useI18n } from "~/i18n/context";
Expand Down Expand Up @@ -48,11 +56,44 @@ export function BalanceBox(props: { loading?: boolean; small?: boolean }) {
const navigate = useNavigate();
const i18n = useI18n();

const [nodeManagerLoading, setNodeManagerLoading] = createSignal(false);

const lightningBalance = () => state.balance?.lightning || 0n;

const totalOnchain = () =>
(state.balance?.confirmed || 0n) +
(state.balance?.unconfirmed || 0n) +
(state.balance?.force_close || 0n);

const [hasSelfCustody, { refetch }] = createResource(async () => {
// short circuit if we have a balance
if (totalOnchain() > 0 || state.balance?.lightning || 0n > 0n) {
return true;
}

// otherwise check if we have created a node
const nodes: string[] = await state.mutiny_wallet?.list_nodes();
return nodes.length > 0;
});

const createNodeManager = async () => {
if (confirm("Pass this test:")) {
setNodeManagerLoading(true);
await state.mutiny_wallet?.create_node_manager_if_needed();

Check failure on line 82 in src/components/BalanceBox.tsx

View workflow job for this annotation

GitHub Actions / code_quality

Property 'create_node_manager_if_needed' does not exist on type 'MutinyWallet'.

Check failure on line 82 in src/components/BalanceBox.tsx

View workflow job for this annotation

GitHub Actions / Build APK

Property 'create_node_manager_if_needed' does not exist on type 'MutinyWallet'.

Check failure on line 82 in src/components/BalanceBox.tsx

View workflow job for this annotation

GitHub Actions / Build iOS

Property 'create_node_manager_if_needed' does not exist on type 'MutinyWallet'.
await refetch();
setNodeManagerLoading(false);
}
};

const removeNodeManager = async () => {
if (confirm("Are you sure:")) {
setNodeManagerLoading(true);
await state.mutiny_wallet?.remove_node_manager();

Check failure on line 91 in src/components/BalanceBox.tsx

View workflow job for this annotation

GitHub Actions / code_quality

Property 'remove_node_manager' does not exist on type 'MutinyWallet'.

Check failure on line 91 in src/components/BalanceBox.tsx

View workflow job for this annotation

GitHub Actions / Build APK

Property 'remove_node_manager' does not exist on type 'MutinyWallet'.

Check failure on line 91 in src/components/BalanceBox.tsx

View workflow job for this annotation

GitHub Actions / Build iOS

Property 'remove_node_manager' does not exist on type 'MutinyWallet'.
await refetch();
setNodeManagerLoading(false);
}
};

return (
<VStack>
<Switch>
Expand Down Expand Up @@ -108,70 +149,115 @@ export function BalanceBox(props: { loading?: boolean; small?: boolean }) {
</Match>
</Switch>
<MediumHeader>{i18n.t("profile.self_custody")}</MediumHeader>
<FancyCard>
<Show when={!props.loading} fallback={<LoadingShimmer />}>
<Switch>
<Match when={state.safe_mode}>
<div class="flex flex-col gap-1">
<InfoBox accent="red">
{i18n.t("common.error_safe_mode")}
</InfoBox>
</div>
</Match>
<Match when={true}>
<div class="flex flex-col gap-1">
<div class="text-2xl">
<AmountSats
amountSats={
state.balance?.lightning || 0
}
icon="lightning"
denominationSize="lg"
/>
</div>
<div class="text-lg text-white/70">
<AmountFiat
amountSats={
state.balance?.lightning || 0
}
denominationSize="sm"
/>
</div>
</div>
</Match>
</Switch>
</Show>
<hr class="my-2 border-m-grey-750" />
<Show when={!props.loading} fallback={<LoadingShimmer />}>
<div class="flex justify-between">
<div class="flex flex-col gap-1">
<div class="text-2xl">
<AmountSats
amountSats={totalOnchain()}
icon="chain"
denominationSize="lg"
/>
</div>
<div class="text-lg text-white/70">
<AmountFiat
amountSats={totalOnchain()}
denominationSize="sm"
/>
</div>
</div>
<div class="flex flex-col items-end justify-between gap-1">
<Show when={state.balance?.unconfirmed != 0n}>
<Indicator>
{i18n.t("common.pending")}
</Indicator>
<Suspense>
<Switch>
<Match when={hasSelfCustody()}>
<FancyCard>
<Show
when={!props.loading}
fallback={<LoadingShimmer />}
>
<Switch>
<Match when={state.safe_mode}>
<div class="flex flex-col gap-1">
<InfoBox accent="red">
{i18n.t(
"common.error_safe_mode"
)}
</InfoBox>
</div>
</Match>
<Match when={true}>
<div class="flex flex-col gap-1">
<div class="text-2xl">
<AmountSats
amountSats={lightningBalance()}
icon="lightning"
denominationSize="lg"
/>
</div>
<div class="text-lg text-white/70">
<AmountFiat
amountSats={
state.balance
?.lightning || 0
}
denominationSize="sm"
/>
</div>
</div>
</Match>
</Switch>
</Show>
<Show when={state.balance?.unconfirmed === 0n}>
<div />
<hr class="my-2 border-m-grey-750" />
<Show
when={!props.loading}
fallback={<LoadingShimmer />}
>
<div class="flex justify-between">
<div class="flex flex-col gap-1">
<div class="text-2xl">
<AmountSats
amountSats={totalOnchain()}
icon="chain"
denominationSize="lg"
/>
</div>
<div class="text-lg text-white/70">
<AmountFiat
amountSats={totalOnchain()}
denominationSize="sm"
/>
</div>
</div>
<div class="flex flex-col items-end justify-between gap-1">
<Show
when={
state.balance?.unconfirmed != 0n
}
>
<Indicator>
{i18n.t("common.pending")}
</Indicator>
</Show>
<Show
when={
state.balance?.unconfirmed ===
0n
}
>
<div />
</Show>
</div>
</div>
<Show
when={
totalOnchain() === 0n &&
lightningBalance() === 0n &&
state.federations &&
state.federations.length
}
>
<SubtleButton
onClick={removeNodeManager}
loading={nodeManagerLoading()}
>
<Trash class="h-4 w-4" />
</SubtleButton>
</Show>
</Show>
</div>
</div>
</Show>
</FancyCard>
</FancyCard>
</Match>
<Match when={true}>
<SubtleButton
onClick={createNodeManager}
loading={nodeManagerLoading()}
>
<Plus class="h-4 w-4" />
</SubtleButton>
</Match>
</Switch>
</Suspense>
</VStack>
);
}
3 changes: 3 additions & 0 deletions src/components/HomePrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ export function HomePrompt() {
lsps_token: params.token
};
try {
// If we're setting an LSPS config, we want a node manager
await state.mutiny_wallet?.create_node_manager_if_needed();

Check failure on line 72 in src/components/HomePrompt.tsx

View workflow job for this annotation

GitHub Actions / code_quality

Property 'create_node_manager_if_needed' does not exist on type 'MutinyWallet'.

Check failure on line 72 in src/components/HomePrompt.tsx

View workflow job for this annotation

GitHub Actions / Build APK

Property 'create_node_manager_if_needed' does not exist on type 'MutinyWallet'.

Check failure on line 72 in src/components/HomePrompt.tsx

View workflow job for this annotation

GitHub Actions / Build iOS

Property 'create_node_manager_if_needed' does not exist on type 'MutinyWallet'.

await state.mutiny_wallet?.change_lsp(
values.lsp ? values.lsp : undefined,
values.lsps_connection_string
Expand Down
13 changes: 9 additions & 4 deletions src/routes/Send.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { MutinyInvoice, TagItem } from "@mutinywallet/mutiny-wasm";
import { useLocation, useNavigate, useSearchParams } from "@solidjs/router";
import {
createAsync,
useLocation,
useNavigate,
useSearchParams
} from "@solidjs/router";
import { Eye, EyeOff, Link, X, Zap } from "lucide-solid";
import {
createEffect,
Expand Down Expand Up @@ -300,7 +305,7 @@ export function Send() {
});

// Rerun every time the amount changes if we're onchain
const feeEstimate = createMemo(() => {
const feeEstimate = createAsync(async () => {
if (
source() === "onchain" &&
amountSats() &&
Expand All @@ -310,12 +315,12 @@ export function Send() {
try {
// If max we want to use the sweep fee estimator
if (isMax()) {
return state.mutiny_wallet?.estimate_sweep_tx_fee(
return await state.mutiny_wallet?.estimate_sweep_tx_fee(
address()!
);
}

return state.mutiny_wallet?.estimate_tx_fee(
return await state.mutiny_wallet?.estimate_tx_fee(
address()!,
amountSats(),
undefined
Expand Down
3 changes: 3 additions & 0 deletions src/routes/setup/AddFederation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@ import {
MutinyWalletGuard
} from "~/components";
import { useI18n } from "~/i18n/context";
import { useMegaStore } from "~/state/megaStore";

import { AddFederationForm } from "../settings";

export function AddFederation() {
const i18n = useI18n();
const navigate = useNavigate();
const [state, _actions] = useMegaStore();

const [confirmOpen, setConfirmOpen] = createSignal(false);

async function handleSkip() {
await state.mutiny_wallet?.create_node_manager_if_needed();

Check failure on line 24 in src/routes/setup/AddFederation.tsx

View workflow job for this annotation

GitHub Actions / code_quality

Property 'create_node_manager_if_needed' does not exist on type 'MutinyWallet'.

Check failure on line 24 in src/routes/setup/AddFederation.tsx

View workflow job for this annotation

GitHub Actions / Build APK

Property 'create_node_manager_if_needed' does not exist on type 'MutinyWallet'.

Check failure on line 24 in src/routes/setup/AddFederation.tsx

View workflow job for this annotation

GitHub Actions / Build iOS

Property 'create_node_manager_if_needed' does not exist on type 'MutinyWallet'.
navigate("/");
}

Expand Down
17 changes: 16 additions & 1 deletion src/state/megaStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,21 @@ export const Provider: ParentComponent = (props) => {
},
60 * 1000 * state.price_sync_backoff_multiple
); // Poll every minute * backoff multiple

// handle if it is an empty wallet (we have no federations or nodes), take them to the add federation page.
// This will either force them to pick a federation or create a node manager.
const nodes: string[] = await state.mutiny_wallet.list_nodes();
const numFederations = state.federations
? state.federations.length
: 0;

if (nodes.length === 0 && numFederations === 0) {
navigate("/addfederation");
} else {
console.log("nodes", nodes);
console.log("federations", numFederations);
navigate("/");
}
},
async deleteMutinyWallet(): Promise<void> {
try {
Expand Down Expand Up @@ -571,7 +586,7 @@ export const Provider: ParentComponent = (props) => {
await actions.preSetup();

setState({ load_stage: "checking_for_existing_wallet" });
const existing = await MutinyWallet.has_node_manager();
const existing = await MutinyWallet.is_wallet_present();

Check failure on line 589 in src/state/megaStore.tsx

View workflow job for this annotation

GitHub Actions / code_quality

Property 'is_wallet_present' does not exist on type 'typeof MutinyWallet'.

Check failure on line 589 in src/state/megaStore.tsx

View workflow job for this annotation

GitHub Actions / Build APK

Property 'is_wallet_present' does not exist on type 'typeof MutinyWallet'.

Check failure on line 589 in src/state/megaStore.tsx

View workflow job for this annotation

GitHub Actions / Build iOS

Property 'is_wallet_present' does not exist on type 'typeof MutinyWallet'.

if (!existing && !params.skip_setup) {
navigate("/setup");
Expand Down

0 comments on commit 8d1b9ff

Please sign in to comment.