diff --git a/.env b/.env
new file mode 100644
index 0000000..e30db72
--- /dev/null
+++ b/.env
@@ -0,0 +1,3 @@
+VITE_NETWORK="regtest"
+VITE_PROXY="wss://p.mutinywallet.com"
+VITE_ESPLORA="http://localhost:3003"
\ No newline at end of file
diff --git a/package.json b/package.json
index c2b7f9c..d979d11 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"dev": "solid-start dev",
"build": "solid-start build",
"start": "solid-start start",
- "lint": "eslint . --ext .ts,.tsx,.js"
+ "lint": "eslint src --ext .ts,.tsx,.js"
},
"type": "module",
"devDependencies": {
@@ -20,10 +20,12 @@
"typescript": "^4.9.5",
"vite": "^4.2.1",
"vite-plugin-pwa": "^0.14.7",
+ "vite-plugin-wasm": "^3.2.2",
"workbox-window": "^6.5.4"
},
"dependencies": {
"@motionone/solid": "^10.16.0",
+ "@mutinywallet/node-manager": "^0.2.2",
"@nostr-dev-kit/ndk": "^0.0.13",
"@solidjs/meta": "^0.28.4",
"@solidjs/router": "^0.8.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fa404c6..f1678ee 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4,6 +4,9 @@ dependencies:
'@motionone/solid':
specifier: ^10.16.0
version: 10.16.0(solid-js@1.7.1)
+ '@mutinywallet/node-manager':
+ specifier: ^0.2.2
+ version: 0.2.2
'@nostr-dev-kit/ndk':
specifier: ^0.0.13
version: 0.0.13(typescript@4.9.5)
@@ -69,6 +72,9 @@ devDependencies:
vite-plugin-pwa:
specifier: ^0.14.7
version: 0.14.7(vite@4.2.1)(workbox-build@6.5.4)(workbox-window@6.5.4)
+ vite-plugin-wasm:
+ specifier: ^3.2.2
+ version: 3.2.2(vite@4.2.1)
workbox-window:
specifier: ^6.5.4
version: 6.5.4
@@ -1534,6 +1540,10 @@ packages:
tslib: 2.5.0
dev: false
+ /@mutinywallet/node-manager@0.2.2:
+ resolution: {integrity: sha512-N/zZIXFV7eg6cv2oIdWZPZgqAuGU9tRyqYJPI1oAkDV74weTWQedwOYco9ABbTIyavqYlTv+fiEjieS2RMCLKg==}
+ dev: false
+
/@noble/curves@0.8.3:
resolution: {integrity: sha512-OqaOf4RWDaCRuBKJLDURrgVxjLmneGsiCXGuzYB5y95YithZMA6w4uk34DHSm0rKMrrYiaeZj48/81EvaAScLQ==}
dependencies:
@@ -4928,6 +4938,14 @@ packages:
transitivePeerDependencies:
- supports-color
+ /vite-plugin-wasm@3.2.2(vite@4.2.1):
+ resolution: {integrity: sha512-cdbBUNR850AEoMd5nvLmnyeq63CSfoP1ctD/L2vLk/5+wsgAPlAVAzUK5nGKWO/jtehNlrSSHLteN+gFQw7VOA==}
+ peerDependencies:
+ vite: ^2 || ^3 || ^4
+ dependencies:
+ vite: 4.2.1(@types/node@18.15.11)
+ dev: true
+
/vite@4.2.1(@types/node@18.15.11):
resolution: {integrity: sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==}
engines: {node: ^14.18.0 || >=16.0.0}
diff --git a/src/components/App.tsx b/src/components/App.tsx
index 1f82417..0fae68e 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -1,4 +1,4 @@
-import { createSignal, For } from "solid-js";
+import { For } from "solid-js";
import { A } from "solid-start";
import { Motion, Presence } from "@motionone/solid";
@@ -7,6 +7,7 @@ import mutiny_m from '~/assets/icons/m.svg';
import scan from '~/assets/icons/scan.svg';
import settings from '~/assets/icons/settings.svg';
import send from '~/assets/icons/send.svg';
+import BalanceBox from "./BalanceBox";
// TODO: use this reload prompt for real
// import ReloadPrompt from "./Reload";
@@ -26,7 +27,6 @@ function ActivityItem() {
}
export default function App() {
- const [_isOpen, setOpen] = createSignal(false);
return (
-
-
);
}
diff --git a/src/components/BalanceBox.tsx b/src/components/BalanceBox.tsx
new file mode 100644
index 0000000..4b4680f
--- /dev/null
+++ b/src/components/BalanceBox.tsx
@@ -0,0 +1,45 @@
+import { Motion, Presence } from "@motionone/solid";
+import { MutinyBalance } from "@mutinywallet/node-manager";
+
+import { useNodeManager } from "~/state/nodeManagerState";
+
+function prettyPrintAmount(n?: number | bigint): string {
+ if (!n || n.valueOf() === 0) {
+ return "0"
+ }
+ return n.toLocaleString().replaceAll(",", "_")
+}
+
+function prettyPrintBalance(b: MutinyBalance): string {
+ return prettyPrintAmount(b.confirmed.valueOf() + b.lightning.valueOf())
+}
+
+export default function BalanceBox() {
+ const { balance, refetchBalance } = useNodeManager();
+
+ return (
+
+
+
+
+
+
+ {balance() && prettyPrintBalance(balance())} SAT
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/logic/nodeManagerSetup.ts b/src/logic/nodeManagerSetup.ts
new file mode 100644
index 0000000..9009b3f
--- /dev/null
+++ b/src/logic/nodeManagerSetup.ts
@@ -0,0 +1,76 @@
+
+import init, { NodeManager } from '@mutinywallet/node-manager';
+
+export type NodeManagerSettingStrings = {
+ network?: string, proxy?: string, esplora?: string
+}
+
+export function getExistingSettings(): NodeManagerSettingStrings {
+ 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;
+
+ return { network, proxy, esplora }
+}
+
+export async function setAndGetMutinySettings(settings?: NodeManagerSettingStrings): Promise
{
+ let { network, proxy, esplora } = settings || {};
+
+ const existingSettings = getExistingSettings();
+ try {
+ network = network || existingSettings.network;
+ proxy = proxy || existingSettings.proxy;
+ esplora = esplora || existingSettings.esplora;
+
+ 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);
+
+ return { network, proxy, esplora }
+ } catch (error) {
+ console.error(error)
+ throw error
+ }
+}
+
+export async function checkForWasm() {
+ try {
+ if (typeof WebAssembly === "object"
+ && typeof WebAssembly.instantiate === "function") {
+ const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
+ if (!(module instanceof WebAssembly.Module)) {
+ throw new Error("Couldn't instantiate WASM Module")
+ }
+ } else {
+ throw new Error("No WebAssembly global object found")
+ }
+ } catch (e) {
+ console.error(e)
+ }
+}
+
+export async function setupNodeManager(settings?: NodeManagerSettingStrings): Promise {
+ const _ = await init();
+
+ console.time("Setup");
+ console.log("Starting setup...")
+ const { network, proxy, esplora } = await setAndGetMutinySettings(settings)
+ console.log("Initializing Node Manager")
+ console.log("Using network", network);
+ console.log("Using proxy", proxy);
+ console.log("Using esplora address", esplora);
+
+ const nodeManager = await new NodeManager("", undefined, proxy, network, esplora)
+
+ const nodes = await nodeManager.list_nodes();
+
+ // If we don't have any nodes yet, create one
+ if (!nodes.length) {
+ await nodeManager?.new_node()
+ }
+
+ return nodeManager
+}
\ No newline at end of file
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index 93170e8..46a5c26 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -4,6 +4,7 @@ import { Accessor, createEffect, createResource, Setter, createSignal, Switch, M
import { WaitlistAlreadyIn } from "~/components/waitlist/WaitlistAlreadyIn";
import WaitlistForm from "~/components/waitlist/WaitlistForm";
import ReloadPrompt from "~/components/Reload";
+import { NodeManagerProvider } from "~/state/nodeManagerState";
function createWaitListSignal(): [Accessor, Setter] {
const [state, setState] = createSignal("");
@@ -34,7 +35,9 @@ export default function Home() {
Loading...>} >
-
+
+
+
diff --git a/src/state/nodeManagerState.tsx b/src/state/nodeManagerState.tsx
new file mode 100644
index 0000000..3eaa042
--- /dev/null
+++ b/src/state/nodeManagerState.tsx
@@ -0,0 +1,31 @@
+import { NodeManager } from "@mutinywallet/node-manager";
+import { createContext, JSX, useContext, createResource } from "solid-js";
+import { setupNodeManager } from "~/logic/nodeManagerSetup";
+
+const NodeManagerContext = createContext();
+
+export function NodeManagerProvider(props: { children: JSX.Element }) {
+ const [nodeManager] = createResource({}, setupNodeManager);
+
+ const fetchBalance = async (nm: NodeManager) => {
+ console.log("refetching balance");
+ const balance = await nm.get_balance();
+ return balance
+ };
+
+ const [balance, { refetch }] = createResource(nodeManager, fetchBalance);
+
+ const value = {
+ nodeManager,
+ balance,
+ refetchBalance: refetch
+ };
+
+ return (
+
+ {props.children}
+
+ )
+}
+
+export function useNodeManager() { return useContext(NodeManagerContext); }
diff --git a/vite.config.ts b/vite.config.ts
index b2623c7..a65f66e 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,10 +1,12 @@
import solid from "solid-start/vite";
import { defineConfig } from "vite";
-import { VitePWA, VitePWAOptions } from 'vite-plugin-pwa'
+import { VitePWA, VitePWAOptions } from "vite-plugin-pwa";
+import wasm from "vite-plugin-wasm";
import * as path from 'path'
const pwaOptions: Partial = {
+ base: '/',
registerType: "autoUpdate",
devOptions: {
enabled: true
@@ -40,8 +42,12 @@ export default defineConfig({
server: {
port: 3420,
},
- plugins: [solid({ ssr: false }), VitePWA(pwaOptions)],
+ plugins: [wasm(), solid({ ssr: false }), VitePWA(pwaOptions)],
resolve: {
alias: [{ find: '~', replacement: path.resolve(__dirname, './src') }]
- }
+ },
+ optimizeDeps: {
+ // This is necessary because otherwise `vite dev` can't find the wasm
+ exclude: ["@mutinywallet/node-manager"],
+ },
});