diff --git a/src/components/BetaWarningModal.tsx b/src/components/BetaWarningModal.tsx index 5d5a854..af6a5bc 100644 --- a/src/components/BetaWarningModal.tsx +++ b/src/components/BetaWarningModal.tsx @@ -3,8 +3,8 @@ import { ParentComponent, createSignal } from "solid-js"; import { DIALOG_CONTENT, DIALOG_POSITIONER, OVERLAY } from "./DetailsModal"; import { ModalCloseButton, SmallHeader } from "./layout"; import { ExternalLink } from "./layout/ExternalLink"; -import { getExistingSettings } from "~/logic/mutinyWalletSetup"; import { useI18n } from "~/i18n/context"; +import { useMegaStore } from "~/state/megaStore"; export function BetaWarningModal() { const i18n = useI18n(); @@ -34,9 +34,11 @@ export const WarningModal: ParentComponent<{ linkText: string; title: string; }> = (props) => { + const [state, _actions] = useMegaStore(); + const [open, setOpen] = createSignal( localStorage.getItem("betaWarned") !== "true" && - getExistingSettings().network === "bitcoin" + state.settings?.network === "bitcoin" ); function close() { diff --git a/src/components/DecryptDialog.tsx b/src/components/DecryptDialog.tsx index ac8809f..1196d81 100644 --- a/src/components/DecryptDialog.tsx +++ b/src/components/DecryptDialog.tsx @@ -19,7 +19,7 @@ export function DecryptDialog() { e.preventDefault(); setLoading(true); try { - await actions.setupMutinyWallet(undefined, password()); + await actions.setup(password()); // If we get this far and the state stills wants a password that means the password was wrong if (state.needs_password) { diff --git a/src/logic/mutinyWalletSetup.ts b/src/logic/mutinyWalletSetup.ts index cddbfa1..18b4e1d 100644 --- a/src/logic/mutinyWalletSetup.ts +++ b/src/logic/mutinyWalletSetup.ts @@ -3,8 +3,9 @@ import initMutinyWallet, { MutinyWallet } from "@mutinywallet/mutiny-wasm"; export type Network = "bitcoin" | "testnet" | "regtest" | "signet"; + export type MutinyWalletSettingStrings = { - network?: Network; + network?: string; proxy?: string; esplora?: string; rgs?: string; @@ -15,116 +16,110 @@ export type MutinyWalletSettingStrings = { scorer?: string; }; -export function getExistingSettings(): MutinyWalletSettingStrings { - const network = - localStorage.getItem("MUTINY_SETTINGS_network") || - import.meta.env.VITE_NETWORK; - const proxy = - localStorage.getItem("MUTINY_SETTINGS_proxy") || - import.meta.env.VITE_PROXY; - const esplora = - localStorage.getItem("MUTINY_SETTINGS_esplora") || - import.meta.env.VITE_ESPLORA; - const rgs = - localStorage.getItem("MUTINY_SETTINGS_rgs") || import.meta.env.VITE_RGS; - const lsp = - localStorage.getItem("MUTINY_SETTINGS_lsp") || import.meta.env.VITE_LSP; - const auth = - localStorage.getItem("MUTINY_SETTINGS_auth") || - import.meta.env.VITE_AUTH; - const subscriptions = - localStorage.getItem("MUTINY_SETTINGS_subscriptions") || - import.meta.env.VITE_SUBSCRIPTIONS; - const storage = - localStorage.getItem("MUTINY_SETTINGS_storage") || - import.meta.env.VITE_STORAGE; - const scorer = - localStorage.getItem("MUTINY_SETTINGS_scorer") || - import.meta.env.VITE_SCORER; +const SETTINGS_KEYS = [ + { + name: "network", + storageKey: "USER_SETTINGS_network", + default: import.meta.env.VITE_NETWORK + }, + { + name: "proxy", + storageKey: "USER_SETTINGS_proxy", + default: import.meta.env.VITE_PROXY + }, + { + name: "esplora", + storageKey: "USER_SETTINGS_esplora", + default: import.meta.env.VITE_ESPLORA + }, + { + name: "rgs", + storageKey: "USER_SETTINGS_rgs", + default: import.meta.env.VITE_RGS + }, + { + name: "lsp", + storageKey: "USER_SETTINGS_lsp", + default: import.meta.env.VITE_LSP + }, + { + name: "auth", + storageKey: "USER_SETTINGS_auth", + default: import.meta.env.VITE_AUTH + }, + { + name: "subscriptions", + storageKey: "USER_SETTINGS_subscriptions", + default: import.meta.env.VITE_SUBSCRIPTIONS + }, + { + name: "storage", + storageKey: "USER_SETTINGS_storage", + default: import.meta.env.VITE_STORAGE + }, + { + name: "scorer", + storageKey: "USER_SETTINGS_scorer", + default: import.meta.env.VITE_SCORER + } +]; - return { - network, - proxy, - esplora, - rgs, - lsp, - auth, - subscriptions, - storage, - scorer - }; +function getItemOrDefault( + storageKey: string, + defaultValue: string +): string | undefined { + const item = localStorage.getItem(storageKey); + if (item === "") { + return undefined; + } else if (item === null) { + return defaultValue; + } else { + return item; + } } -export async function setAndGetMutinySettings( - settings?: MutinyWalletSettingStrings -): Promise { - let { - network, - proxy, - esplora, - rgs, - lsp, - auth, - subscriptions, - storage, - scorer - } = settings || {}; - - const existingSettings = getExistingSettings(); - - try { - network = network || existingSettings.network; - proxy = proxy || existingSettings.proxy; - esplora = esplora || existingSettings.esplora; - rgs = rgs || existingSettings.rgs; - lsp = lsp || existingSettings.lsp; - auth = auth || existingSettings.auth; - subscriptions = subscriptions || existingSettings.subscriptions; - storage = storage || existingSettings.storage; - scorer = scorer || existingSettings.scorer; - - if (!network || !proxy || !esplora) { - throw new Error( - "Missing a default setting for network, proxy, or esplora. Check your .env file to make sure it looks like .env.sample" - ); - } - - localStorage.setItem("MUTINY_SETTINGS_network", network); - localStorage.setItem("MUTINY_SETTINGS_proxy", proxy); - localStorage.setItem("MUTINY_SETTINGS_esplora", esplora); - - if (!rgs || !lsp) { - console.warn("RGS or LSP not set"); - } - - rgs && localStorage.setItem("MUTINY_SETTINGS_rgs", rgs); - lsp && localStorage.setItem("MUTINY_SETTINGS_lsp", lsp); - auth && localStorage.setItem("MUTINY_SETTINGS_auth", auth); - subscriptions && - localStorage.setItem( - "MUTINY_SETTINGS_subscriptions", - subscriptions - ); - storage && localStorage.setItem("MUTINY_SETTINGS_storage", storage); - scorer && localStorage.setItem("MUTINY_SETTINGS_scorer", scorer); - - return { - network, - proxy, - esplora, - rgs, - lsp, - auth, - subscriptions, - storage, - scorer - }; - } catch (error) { - console.error(error); - throw error; +function setItemIfNotDefault( + key: string, + override: string, + defaultValue: string +) { + if (override === defaultValue) { + localStorage.removeItem(key); + } else { + localStorage.setItem(key, override); } } +export async function getSettings() { + const settings = {}; + + SETTINGS_KEYS.forEach(({ name, storageKey, default: defaultValue }) => { + const n = name as keyof MutinyWalletSettingStrings; + const item = getItemOrDefault(storageKey, defaultValue); + settings[n] = item as string; + }); + + if (!settings.network || !settings.proxy || !settings.esplora) { + throw new Error( + "Missing a default setting for network, proxy, or esplora. Check your .env file to make sure it looks like .env.sample" + ); + } + + return settings; +} + +export async function setSettings(newSettings: MutinyWalletSettingStrings) { + SETTINGS_KEYS.forEach(({ name, storageKey, default: defaultValue }) => { + const n = name as keyof MutinyWalletSettingStrings; + const override = newSettings[n]; + // If the value is in the newSettings, and it's not the default, set it in localstorage + // Also, "" is a valid value, so we only want to reject undefined + if (override !== undefined) { + setItemIfNotDefault(storageKey, override, defaultValue); + } + }); +} + export async function checkForWasm() { try { if ( @@ -167,10 +162,11 @@ export async function initializeWasm() { } export async function setupMutinyWallet( - settings?: MutinyWalletSettingStrings, + settings: MutinyWalletSettingStrings, password?: string ): Promise { console.log("Starting setup..."); + const { network, proxy, @@ -181,7 +177,8 @@ export async function setupMutinyWallet( subscriptions, storage, scorer - } = await setAndGetMutinySettings(settings); + } = settings; + console.log("Initializing Mutiny Manager"); console.log("Using network", network); console.log("Using proxy", proxy); @@ -192,6 +189,7 @@ export async function setupMutinyWallet( console.log("Using subscriptions address", subscriptions); console.log("Using storage address", storage); console.log("Using scorer address", scorer); + const mutinyWallet = await new MutinyWallet( // Password password ? password : undefined, diff --git a/src/routes/Swap.tsx b/src/routes/Swap.tsx index 4dff052..7e3eaa3 100644 --- a/src/routes/Swap.tsx +++ b/src/routes/Swap.tsx @@ -75,10 +75,7 @@ export default function Swap() { } const hasLsp = () => { - return ( - !!localStorage.getItem("MUTINY_SETTINGS_lsp") || - !!import.meta.env.VITE_LSP - ); + return !!state.settings?.lsp; }; const getPeers = async () => { diff --git a/src/routes/settings/Servers.tsx b/src/routes/settings/Servers.tsx index 2d38a7a..b0027ed 100644 --- a/src/routes/settings/Servers.tsx +++ b/src/routes/settings/Servers.tsx @@ -2,8 +2,7 @@ import { createForm, url } from "@modular-forms/solid"; import { TextField } from "~/components/layout/TextField"; import { MutinyWalletSettingStrings, - getExistingSettings, - setAndGetMutinySettings + setSettings } from "~/logic/mutinyWalletSetup"; import { Button, @@ -20,19 +19,19 @@ import { ExternalLink } from "~/components/layout/ExternalLink"; import { BackLink } from "~/components/layout/BackLink"; import NavBar from "~/components/NavBar"; import { useI18n } from "~/i18n/context"; +import { useMegaStore } from "~/state/megaStore"; export function SettingsStringsEditor() { const i18n = useI18n(); - const existingSettings = getExistingSettings(); + const [state, _actions] = useMegaStore(); const [settingsForm, { Form, Field }] = createForm({ - initialValues: existingSettings + initialValues: state.settings }); async function handleSubmit(values: MutinyWalletSettingStrings) { try { - const newSettings = { ...existingSettings, ...values }; - await setAndGetMutinySettings(newSettings); + await setSettings(values); window.location.reload(); } catch (e) { console.error(e); diff --git a/src/state/megaStore.tsx b/src/state/megaStore.tsx index d38f7e2..9a124d5 100644 --- a/src/state/megaStore.tsx +++ b/src/state/megaStore.tsx @@ -13,6 +13,7 @@ import { createStore } from "solid-js/store"; import { MutinyWalletSettingStrings, doubleInitDefense, + getSettings, initializeWasm, setupMutinyWallet } from "~/logic/mutinyWalletSetup"; @@ -51,12 +52,10 @@ export type MegaStore = [ readonly mutiny_plus: boolean; needs_password: boolean; load_stage: LoadStage; + settings?: MutinyWalletSettingStrings; }, { - setupMutinyWallet( - settings?: MutinyWalletSettingStrings, - password?: string - ): Promise; + setup(password?: string): Promise; deleteMutinyWallet(): Promise; setScanResult(scan_result: ParsedParams | undefined): void; sync(): Promise; @@ -95,7 +94,8 @@ export const Provider: ParentComponent = (props) => { else return true; }, needs_password: false, - load_stage: "fresh" as LoadStage + load_stage: "fresh" as LoadStage, + settings: undefined as MutinyWalletSettingStrings | undefined }); const actions = { @@ -119,10 +119,7 @@ export const Provider: ParentComponent = (props) => { console.error(e); } }, - async setupMutinyWallet( - settings?: MutinyWalletSettingStrings, - password?: string - ): Promise { + async setup(password?: string): Promise { try { // If we're already in an error state there should be no reason to continue if (state.setup_error) { @@ -139,11 +136,16 @@ export const Provider: ParentComponent = (props) => { await initializeWasm(); setState({ load_stage: "setup" }); + const settings = await getSettings(); + const mutinyWallet = await setupMutinyWallet( settings, password ); + // Give other components access to settings via the store + setState({ settings: settings }); + // If we get this far then we don't need the password anymore setState({ needs_password: false }); @@ -280,7 +282,7 @@ export const Provider: ParentComponent = (props) => { console.log("running setup node manager..."); actions - .setupMutinyWallet() + .setup() .then(() => console.log("node manager setup done")); // Setup an event listener to stop the mutiny wallet when the page unloads