Skip to content
This repository was archived by the owner on Apr 21, 2025. It is now read-only.

Commit 24195ba

Browse files
committed
Optional node manager
1 parent f5c0a83 commit 24195ba

File tree

6 files changed

+211
-81
lines changed

6 files changed

+211
-81
lines changed

src/components/BalanceBox.tsx

Lines changed: 159 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import { A, useNavigate } from "@solidjs/router";
2-
import { Shuffle, Users } from "lucide-solid";
3-
import { createMemo, Match, Show, Suspense, Switch } from "solid-js";
2+
import { Plus, Shuffle, Trash, Users } from "lucide-solid";
3+
import {
4+
createMemo,
5+
createResource,
6+
createSignal,
7+
Match,
8+
Show,
9+
Suspense,
10+
Switch
11+
} from "solid-js";
412

513
import {
614
AmountFiat,
@@ -11,6 +19,7 @@ import {
1119
InfoBox,
1220
MediumHeader,
1321
NiceP,
22+
SubtleButton,
1423
VStack
1524
} from "~/components";
1625
import { useI18n } from "~/i18n/context";
@@ -47,10 +56,14 @@ const STYLE =
4756
"px-2 py-1 rounded-xl text-sm flex gap-2 items-center font-semibold";
4857

4958
export function BalanceBox(props: { loading?: boolean; small?: boolean }) {
50-
const [state, _actions] = useMegaStore();
59+
const [state, _actions, sw] = useMegaStore();
5160
const navigate = useNavigate();
5261
const i18n = useI18n();
5362

63+
const [nodeManagerLoading, setNodeManagerLoading] = createSignal(false);
64+
65+
const lightningBalance = () => state.balance?.lightning || 0n;
66+
5467
const totalOnchain = createMemo(
5568
() =>
5669
(state.balance?.confirmed || 0n) +
@@ -64,6 +77,35 @@ export function BalanceBox(props: { loading?: boolean; small?: boolean }) {
6477
(state.balance?.unconfirmed || 0n)
6578
);
6679

80+
const [hasSelfCustody, { refetch }] = createResource(async () => {
81+
// short circuit if we have a balance
82+
if (totalOnchain() > 0 || state.balance?.lightning || 0n > 0n) {
83+
return true;
84+
}
85+
86+
// otherwise check if we have created a node
87+
const nodes: string[] = await sw.list_nodes();
88+
return nodes.length > 0;
89+
});
90+
91+
const createNodeManager = async () => {
92+
if (confirm("Pass this test:")) {
93+
setNodeManagerLoading(true);
94+
await sw.create_node_manager_if_needed();
95+
await refetch();
96+
setNodeManagerLoading(false);
97+
}
98+
};
99+
100+
const removeNodeManager = async () => {
101+
if (confirm("Are you sure:")) {
102+
setNodeManagerLoading(true);
103+
await sw.remove_node_manager();
104+
await refetch();
105+
setNodeManagerLoading(false);
106+
}
107+
};
108+
67109
return (
68110
<VStack>
69111
<Switch>
@@ -131,81 +173,123 @@ export function BalanceBox(props: { loading?: boolean; small?: boolean }) {
131173
</Match>
132174
</Switch>
133175
<MediumHeader>{i18n.t("profile.self_custody")}</MediumHeader>
134-
<FancyCard>
135-
<Show when={!props.loading} fallback={<LoadingShimmer />}>
136-
<Switch>
137-
<Match when={state.safe_mode}>
138-
<div class="flex flex-col gap-1">
139-
<InfoBox accent="red">
140-
{i18n.t("common.error_safe_mode")}
141-
</InfoBox>
142-
</div>
143-
</Match>
144-
<Match when={true}>
145-
<div class="flex flex-col gap-1">
146-
<div class="text-2xl">
147-
<AmountSats
148-
amountSats={
149-
state.balance?.lightning || 0
150-
}
151-
icon="lightning"
152-
denominationSize="lg"
153-
/>
154-
</div>
155-
<div class="text-lg text-white/70">
156-
<Suspense>
157-
<AmountFiat
158-
amountSats={
159-
state.balance?.lightning || 0
160-
}
161-
denominationSize="sm"
162-
/>
163-
</Suspense>
164-
</div>
165-
</div>
166-
</Match>
167-
</Switch>
168-
</Show>
169-
<hr class="my-2 border-m-grey-750" />
170-
<Show when={!props.loading} fallback={<LoadingShimmer />}>
171-
<div class="flex justify-between">
172-
<div class="flex flex-col gap-1">
173-
<div class="text-2xl">
174-
<AmountSats
175-
amountSats={totalOnchain()}
176-
icon="chain"
177-
denominationSize="lg"
178-
/>
179-
</div>
180-
<div class="text-lg text-white/70">
181-
<Suspense>
182-
<AmountFiat
183-
amountSats={totalOnchain()}
184-
denominationSize="sm"
185-
/>
186-
</Suspense>
187-
</div>
188-
</div>
189-
<div class="flex flex-col items-end justify-between gap-1">
190-
<Show when={state.balance?.unconfirmed != 0n}>
191-
<Indicator>
192-
{i18n.t("common.pending")}
193-
</Indicator>
194-
</Show>
195-
<Show when={state.balance?.unconfirmed === 0n}>
196-
<div />
176+
<Suspense>
177+
<Switch>
178+
<Match when={hasSelfCustody()}>
179+
<FancyCard>
180+
<Show
181+
when={!props.loading}
182+
fallback={<LoadingShimmer />}
183+
>
184+
<Switch>
185+
<Match when={state.safe_mode}>
186+
<div class="flex flex-col gap-1">
187+
<InfoBox accent="red">
188+
{i18n.t(
189+
"common.error_safe_mode"
190+
)}
191+
</InfoBox>
192+
</div>
193+
</Match>
194+
<Match when={true}>
195+
<div class="flex flex-col gap-1">
196+
<div class="text-2xl">
197+
<AmountSats
198+
amountSats={lightningBalance()}
199+
icon="lightning"
200+
denominationSize="lg"
201+
/>
202+
</div>
203+
<div class="text-lg text-white/70">
204+
<Suspense>
205+
<AmountFiat
206+
amountSats={lightningBalance()}
207+
denominationSize="sm"
208+
/>
209+
</Suspense>
210+
</div>
211+
</div>
212+
</Match>
213+
</Switch>
197214
</Show>
198-
<Show when={usableOnchain() > 0n}>
199-
<div class="self-end justify-self-end">
200-
<A href="/swap" class={STYLE}>
201-
<Shuffle class="h-6 w-6" />
202-
</A>
215+
<hr class="my-2 border-m-grey-750" />
216+
<Show
217+
when={!props.loading}
218+
fallback={<LoadingShimmer />}
219+
>
220+
<div class="flex justify-between">
221+
<div class="flex flex-col gap-1">
222+
<div class="text-2xl">
223+
<AmountSats
224+
amountSats={totalOnchain()}
225+
icon="chain"
226+
denominationSize="lg"
227+
/>
228+
</div>
229+
<div class="text-lg text-white/70">
230+
<Suspense>
231+
<AmountFiat
232+
amountSats={totalOnchain()}
233+
denominationSize="sm"
234+
/>
235+
</Suspense>
236+
</div>
237+
</div>
238+
<div class="flex flex-col items-end justify-between gap-1">
239+
<Show
240+
when={
241+
state.balance?.unconfirmed != 0n
242+
}
243+
>
244+
<Indicator>
245+
{i18n.t("common.pending")}
246+
</Indicator>
247+
</Show>
248+
<Show
249+
when={
250+
state.balance?.unconfirmed ===
251+
0n
252+
}
253+
>
254+
<div />
255+
</Show>
256+
<Show when={usableOnchain() > 0n}>
257+
<div class="self-end justify-self-end">
258+
<A href="/swap" class={STYLE}>
259+
<Shuffle class="h-6 w-6" />
260+
</A>
261+
</div>
262+
</Show>
263+
</div>
203264
</div>
265+
<Show
266+
when={
267+
totalOnchain() === 0n &&
268+
lightningBalance() === 0n &&
269+
state.federations &&
270+
state.federations.length
271+
}
272+
>
273+
<SubtleButton
274+
onClick={removeNodeManager}
275+
loading={nodeManagerLoading()}
276+
>
277+
<Trash class="h-4 w-4" />
278+
</SubtleButton>
279+
</Show>
204280
</Show>
205-
</div>
206-
</div>
207-
</Show>
208-
</FancyCard>
281+
</FancyCard>
282+
</Match>
283+
<Match when={true}>
284+
<SubtleButton
285+
onClick={createNodeManager}
286+
loading={nodeManagerLoading()}
287+
>
288+
<Plus class="h-4 w-4" />
289+
</SubtleButton>
290+
</Match>
291+
</Switch>
292+
</Suspense>
209293
</VStack>
210294
);
211295
}

src/components/HomePrompt.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ export function HomePrompt() {
6868
lsps_token: params.token
6969
};
7070
try {
71+
// If we're setting an LSPS config, we want a node manager
72+
await sw.create_node_manager_if_needed();
73+
7174
await sw.change_lsp(
7275
values.lsp ? values.lsp : undefined,
7376
values.lsps_connection_string

src/routes/SwapLightning.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ export function SwapLightning() {
126126
setLoading(true);
127127
setFeeEstimateWarning(undefined);
128128

129+
await sw.create_node_manager_if_needed();
130+
129131
const mutinyInvoice = await sw.create_sweep_federation_invoice(
130132
isMax() ? undefined : amountSats()
131133
);

src/routes/setup/AddFederation.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,33 @@ import {
66
ConfirmDialog,
77
DefaultMain,
88
ExternalLink,
9-
MutinyWalletGuard
9+
MutinyWalletGuard,
10+
showToast
1011
} from "~/components";
1112
import { useI18n } from "~/i18n/context";
13+
import { useMegaStore } from "~/state/megaStore";
14+
import { eify } from "~/utils";
1215

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

1518
export function AddFederation() {
1619
const i18n = useI18n();
1720
const navigate = useNavigate();
21+
const [_state, _actions, sw] = useMegaStore();
1822

1923
const [confirmOpen, setConfirmOpen] = createSignal(false);
24+
const [confirmLoading, setConfirmLoading] = createSignal(false);
2025

2126
async function handleSkip() {
22-
navigate("/");
27+
setConfirmLoading(true);
28+
try {
29+
await sw.create_node_manager_if_needed();
30+
navigate("/");
31+
} catch (e) {
32+
console.error(e);
33+
setConfirmLoading(false);
34+
showToast(eify(e));
35+
}
2336
}
2437

2538
return (
@@ -41,7 +54,7 @@ export function AddFederation() {
4154
</Button>
4255
<ConfirmDialog
4356
open={confirmOpen()}
44-
loading={false}
57+
loading={confirmLoading()}
4558
onConfirm={handleSkip}
4659
onCancel={() => setConfirmOpen(false)}
4760
>

src/state/megaStore.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export const makeMegaStoreContext = () => {
155155
await sw.initializeWasm();
156156

157157
setState({ load_stage: "checking_for_existing_wallet" });
158-
const existing = await sw.has_node_manager();
158+
const existing = await sw.is_wallet_present();
159159

160160
if (!existing && !searchParams.skip_setup) {
161161
navigate("/setup");
@@ -379,6 +379,17 @@ export const makeMegaStoreContext = () => {
379379
},
380380
60 * 1000 * state.price_sync_backoff_multiple
381381
); // Poll every minute * backoff multiple
382+
383+
// handle if it is an empty wallet (we have no federations or nodes), take them to the add federation page.
384+
// This will either force them to pick a federation or create a node manager.
385+
const nodes: string[] = await sw.list_nodes();
386+
const numFederations = state.federations
387+
? state.federations.length
388+
: 0;
389+
390+
if (nodes.length === 0 && numFederations === 0) {
391+
navigate("/addfederation");
392+
}
382393
},
383394
async deleteMutinyWallet(): Promise<void> {
384395
try {

0 commit comments

Comments
 (0)