diff --git a/src/components/KitchenSink.tsx b/src/components/KitchenSink.tsx index 3f9a1ea..e9ab0cc 100644 --- a/src/components/KitchenSink.tsx +++ b/src/components/KitchenSink.tsx @@ -1,20 +1,198 @@ import { useMegaStore } from "~/state/megaStore"; -import { ButtonLink, Card, SmallHeader } from "~/components/layout"; +import { ButtonLink, Card, Hr, SmallHeader, Button } from "~/components/layout"; import PeerConnectModal from "~/components/PeerConnectModal"; -import { createResource } from "solid-js"; +import { For, Show, Suspense, createResource, createSignal } from "solid-js"; +import { MutinyChannel, MutinyPeer } from "@mutinywallet/node-manager"; +import { TextField } from "@kobalte/core"; +import mempoolTxUrl from "~/utils/mempoolTxUrl"; +import eify from "~/utils/eify"; + +function PeersList() { + const [state, _] = useMegaStore() + + const getPeers = async () => { + return await state.node_manager?.list_peers() as Promise + }; + + const [peers, { refetch }] = createResource(getPeers); + + return ( + <> + + Peers + + {/* By wrapping this in a suspense I don't cause the page to jump to the top */} + + No peers}> + {(peer) => ( +
+                            {JSON.stringify(peer, null, 2)}
+                        
+ )} +
+
+ + + + ) +} + +function ConnectPeer(props: { refetchPeers: () => any }) { + const [state, _] = useMegaStore() + + const [value, setValue] = createSignal(""); + + const onSubmit = async (e: SubmitEvent) => { + e.preventDefault(); + + const peerConnectString = value().trim(); + const nodes = await state.node_manager?.list_nodes(); + const firstNode = nodes[0] as string || "" + + await state.node_manager?.connect_to_peer(firstNode, peerConnectString) + + await props.refetchPeers() + + setValue(""); + }; + + return ( +
+ + Connect Peer + + Expecting something like mutiny:abc123... + + +
+ ) +} + +function ChannelsList() { + const [state, _] = useMegaStore() + + const getChannels = async () => { + return await state.node_manager?.list_channels() as Promise + }; + + const [channels, { refetch }] = createResource(getChannels); + + const network = state.node_manager?.get_network(); + + return ( + <> + + Channels + + {/* By wrapping this in a suspense I don't cause the page to jump to the top */} + + No channels}> + {(channel) => ( + <> +
+                                {JSON.stringify(channel, null, 2)}
+                            
+ + Mempool Link + + + )} + +
+
+ + + + ) +} + +function OpenChannel(props: { refetchChannels: () => any }) { + const [state, _] = useMegaStore() + + const [creationError, setCreationError] = createSignal(); + + const [amount, setAmount] = createSignal(""); + const [peerPubkey, setPeerPubkey] = createSignal(""); + + const [newChannel, setNewChannel] = createSignal(); + + const onSubmit = async (e: SubmitEvent) => { + e.preventDefault(); + + // TODO: figure out why this doesn't catch the rust error + // src/logging.rs:29 + // ERROR: Could not create a signed transaction to open channel with: The invoice or address is on a different network. + try { + const pubkey = peerPubkey().trim(); + const bigAmount = BigInt(amount()); + + const nodes = await state.node_manager?.list_nodes(); + const firstNode = nodes[0] as string || "" + + const new_channel = await state.node_manager?.open_channel(firstNode, pubkey, bigAmount) + + setNewChannel(new_channel) + + await props.refetchChannels() + + setAmount(""); + setPeerPubkey(""); + + } catch (e) { + setCreationError(eify(e)) + } + }; + + return ( + <> +
+ + Pubkey + + + + Amount + + + +
+ +
+                    {JSON.stringify(newChannel()?.outpoint, null, 2)}
+                
+
{newChannel()?.outpoint}
+ + Mempool Link + +
+ +
{creationError()?.message}
+
+ + ) +} export default function KitchenSink() { const [state, _] = useMegaStore() // TODO: would be nice if this was just newest unused address const getNewAddress = async () => { - if (state.node_manager) { - console.log("Getting new address"); - const address = await state.node_manager?.get_new_address(); - return address - } else { - return undefined - } + return await state.node_manager?.get_new_address(); }; const [address] = createResource(getNewAddress); @@ -23,12 +201,10 @@ export default function KitchenSink() { Tap the Faucet - - Peers - - - - +
+ +
+
) } \ No newline at end of file diff --git a/src/components/layout/index.tsx b/src/components/layout/index.tsx index efbda84..b6644d4 100644 --- a/src/components/layout/index.tsx +++ b/src/components/layout/index.tsx @@ -1,6 +1,7 @@ import { ParentComponent } from "solid-js" import Linkify from "./Linkify" import { Button, ButtonLink } from "./Button" +import { Separator } from "@kobalte/core" const SmallHeader: ParentComponent = (props) =>
{props.children}
@@ -34,4 +35,6 @@ const LoadingSpinner = () => { ); } -export { SmallHeader, Card, SafeArea, LoadingSpinner, Button, ButtonLink, Linkify } +const Hr = () => + +export { SmallHeader, Card, SafeArea, LoadingSpinner, Button, ButtonLink, Linkify, Hr } diff --git a/src/utils/eify.ts b/src/utils/eify.ts new file mode 100644 index 0000000..c16f147 --- /dev/null +++ b/src/utils/eify.ts @@ -0,0 +1,10 @@ +/// Sometimes we catch an error as `unknown` so this turns it into an Error. +export default function eify(e: unknown): Error { + if (e instanceof Error) { + return e; + } else if (typeof e === 'string') { + return new Error(e); + } else { + return new Error('Unknown error'); + } +} \ No newline at end of file diff --git a/src/utils/mempoolTxUrl.ts b/src/utils/mempoolTxUrl.ts new file mode 100644 index 0000000..c2f9a53 --- /dev/null +++ b/src/utils/mempoolTxUrl.ts @@ -0,0 +1,21 @@ +export default function mempoolTxUrl(txid?: string, network?: string) { + if (!txid || !network) { + console.error("Problem creating the mempool url") + return "#" + } + + if (network) { + switch (network) { + case "mainnet": + return `https://mempool.space/tx/${txid}` + case "testnet": + return `https://mempool.space/testnet/tx/${txid}` + case "signet": + return `https://mutinynet.com/tx/${txid}` + default: + return `https://mempool.space/tx/${txid}` + } + } + + return `https://mempool.space/tx/${txid}` +} \ No newline at end of file