diff --git a/packages/app/src/Icons/Alby.tsx b/packages/app/src/Icons/Alby.tsx
new file mode 100644
index 00000000..df6723b5
--- /dev/null
+++ b/packages/app/src/Icons/Alby.tsx
@@ -0,0 +1,19 @@
+export default function AlbyIcon(props: { size?: number }) {
+ return ;
+}
\ No newline at end of file
diff --git a/packages/app/src/Icons/Cashu.tsx b/packages/app/src/Icons/Cashu.tsx
new file mode 100644
index 00000000..d30a3a4e
--- /dev/null
+++ b/packages/app/src/Icons/Cashu.tsx
@@ -0,0 +1,45 @@
+export default function CashuIcon(props: { size?: number }) {
+ return
+}
\ No newline at end of file
diff --git a/packages/app/src/Pages/WalletPage.tsx b/packages/app/src/Pages/WalletPage.tsx
index c1bae0c4..b3d8c534 100644
--- a/packages/app/src/Pages/WalletPage.tsx
+++ b/packages/app/src/Pages/WalletPage.tsx
@@ -191,8 +191,8 @@ export default function WalletPage(props: { showHistory: boolean }) {
defaultMessage="{amount} sats"
id="E5ZIPD"
values={{
- big: c => {c},
- small: c => {c},
+ big: c => {c},
+ small: c => {c},
amount: ,
}}
/>
diff --git a/packages/app/src/Pages/settings/Routes.tsx b/packages/app/src/Pages/settings/Routes.tsx
index 7b81020d..6083e6b4 100644
--- a/packages/app/src/Pages/settings/Routes.tsx
+++ b/packages/app/src/Pages/settings/Routes.tsx
@@ -5,7 +5,6 @@ import Preferences from "@/Pages/settings/Preferences";
import Notifications from "@/Pages/settings/Notifications";
import RelayInfo from "@/Pages/settings/RelayInfo";
import AccountsPage from "@/Pages/settings/Accounts";
-import { WalletSettingsRoutes } from "@/Pages/settings/WalletSettings";
import { ManageHandleRoutes } from "@/Pages/settings/handle";
import ExportKeys from "@/Pages/settings/Keys";
import ModerationSettings from "@/Pages/settings/Moderation";
@@ -13,6 +12,7 @@ import { CacheSettings } from "@/Pages/settings/Cache";
import { ReferralsPage } from "@/Pages/settings/Referrals";
import { Outlet } from "react-router-dom";
import { ToolsPage, ToolsPages } from "./tools";
+import { WalletSettingsRoutes } from "./wallet";
const SettingsPage = () => {
return (
diff --git a/packages/app/src/Pages/settings/WalletSettings.css b/packages/app/src/Pages/settings/WalletSettings.css
deleted file mode 100644
index 4d2f85b9..00000000
--- a/packages/app/src/Pages/settings/WalletSettings.css
+++ /dev/null
@@ -1,14 +0,0 @@
-.wallet-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- text-align: center;
- grid-gap: 10px;
-}
-
-.wallet-grid > div {
- cursor: pointer;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: space-between;
-}
diff --git a/packages/app/src/Pages/settings/WalletSettings.tsx b/packages/app/src/Pages/settings/WalletSettings.tsx
index aea1e08f..8db145d6 100644
--- a/packages/app/src/Pages/settings/WalletSettings.tsx
+++ b/packages/app/src/Pages/settings/WalletSettings.tsx
@@ -1,64 +1,71 @@
-import "./WalletSettings.css";
import LndLogo from "@/lnd-logo.png";
+import { ReactNode } from "react";
import { FormattedMessage } from "react-intl";
-import { RouteObject, useNavigate } from "react-router-dom";
+import { useNavigate } from "react-router-dom";
import BlueWallet from "@/Icons/BlueWallet";
-import ConnectLNC from "@/Pages/settings/wallet/LNC";
-import ConnectLNDHub from "@/Pages/settings/wallet/LNDHub";
-import ConnectNostrWallet from "@/Pages/settings/wallet/NWC";
-import ConnectCashu from "@/Pages/settings/wallet/Cashu";
-
import NostrIcon from "@/Icons/Nostrich";
-import WalletPage from "../WalletPage";
+import CashuIcon from "@/Icons/Cashu";
+import AlbyIcon from "@/Icons/Alby";
+import Icon from "@/Icons/Icon";
+import { getAlbyOAuth } from "./wallet/Alby";
+
+const WalletRow = (props: { logo: ReactNode, name: ReactNode, url: string, desc?: ReactNode }) => {
+ const navigate = useNavigate();
+ return
{
+ if (props.url.startsWith("http")) {
+ window.location.href = props.url;
+ } else {
+ navigate(props.url);
+ }
+ }}>
+
+ {props.logo}
+
+
+
{props.name}
+
{props.desc}
+
+
+
+}
const WalletSettings = () => {
- const navigate = useNavigate();
+ const alby = getAlbyOAuth();
return (
<>
-
-
-
navigate("/settings/wallet/lnc")}>
-
-
LND with LNC
-
-
navigate("/settings/wallet/lndhub")}>
-
-
LNDHub
-
-
navigate("/settings/wallet/nwc")}>
-
-
Nostr Wallet Connect
-
+
+ }
+ name="Nostr Wallet Connect"
+ url="/settings/wallet/nwc"
+ desc={} />
+ }
+ name="LND via LNC"
+ url="/settings/wallet/lnc"
+ desc={} />
+ }
+ name="LNDHub"
+ url="/settings/wallet/lndhub"
+ desc={} />
+ }
+ name="Cashu"
+ url="/settings/wallet/cashu"
+ desc={} />
+ }
+ name="Alby"
+ url={alby.authUrl}
+ desc={} />
>
);
};
-export default WalletSettings;
-
-export const WalletSettingsRoutes = [
- {
- path: "/settings/wallet",
- element:
,
- },
- {
- path: "/settings/wallet/lnc",
- element:
,
- },
- {
- path: "/settings/wallet/lndhub",
- element:
,
- },
- {
- path: "/settings/wallet/nwc",
- element:
,
- },
- {
- path: "/settings/wallet/cashu",
- element:
,
- },
-] as Array
;
+export default WalletSettings;
\ No newline at end of file
diff --git a/packages/app/src/Pages/settings/wallet/Alby.tsx b/packages/app/src/Pages/settings/wallet/Alby.tsx
new file mode 100644
index 00000000..ff5b6559
--- /dev/null
+++ b/packages/app/src/Pages/settings/wallet/Alby.tsx
@@ -0,0 +1,98 @@
+import PageSpinner from "@/Element/PageSpinner";
+import { sha256 } from "@noble/hashes/sha256";
+import { randomBytes } from "@noble/hashes/utils";
+import { base64, base64urlnopad, hex } from "@scure/base";
+import { useEffect, useState } from "react";
+import { useLocation } from "react-router-dom";
+
+export default function AlbyOAuth() {
+ const location = useLocation();
+ const alby = getAlbyOAuth();
+ const [error, setError] = useState("");
+
+ async function setupWallet(token: string) {
+ const auth = await alby.getToken(token);
+ console.debug(auth);
+ }
+
+ useEffect(() => {
+ if (location.search) {
+ const params = new URLSearchParams(location.search);
+ const token = params.get("code");
+ if (token) {
+ setupWallet(token).catch(e => {
+ setError((e as Error).message);
+ });
+ }
+ }
+ }, [location]);
+
+ if (!location.search) return;
+ return <>
+ Alby Wallet Connection
+ {!error && }
+ {error && {error}}
+ >
+}
+
+export function getAlbyOAuth() {
+ const clientId = "35EQp6crss";
+ const clientSecret = "DTUPIqOjsjwxZXcJwF5C"
+ const redirectUrl = `${window.location.protocol}//${window.location.host}/settings/wallet/alby`;
+ const scopes = [
+ "invoices:create",
+ "invoices:read",
+ "transactions:read",
+ "balance:read",
+ "payments:send"
+ ];
+
+ const ec = new TextEncoder();
+ const code_verifier = hex.encode(randomBytes(64));
+ window.sessionStorage.setItem("alby-code", code_verifier);
+
+ const params = new URLSearchParams();
+ params.set("client_id", clientId);
+ params.set("response_type", "code");
+ params.set("code_challenge", base64urlnopad.encode(sha256(code_verifier)));
+ params.set("code_challenge_method", "S256");
+ params.set("redirect_uri", redirectUrl);
+ params.set("scope", scopes.join(" "))
+
+ const tokenUrl = "https://api.getalby.com/oauth/token";
+ const authUrl = `https://getalby.com/oauth?${params}`;
+
+ return {
+ tokenUrl,
+ authUrl,
+ getToken: async (token: string) => {
+ const code = window.sessionStorage.getItem("alby-code");
+ if (!code) throw new Error("Alby code is missing!");
+ window.sessionStorage.removeItem("alby-code");
+
+ const form = new URLSearchParams();
+ form.set("client_id", clientId);
+ form.set("code_verifier", code);
+ form.set("grant_type", "authorization_code");
+ form.set("redirect_uri", redirectUrl);
+ form.set("code", token);
+
+ const req = await fetch(tokenUrl, {
+ method: "POST",
+ headers: {
+ "accept": "application/json",
+ "content-type": "application/x-www-form-urlencoded",
+ "authorization": `Basic ${base64.encode(ec.encode(`${clientId}:${clientSecret}`))}`
+ },
+ body: form
+ });
+
+ const data = await req.json();
+ if (req.ok) {
+ return data.access_token as string;
+ } else {
+ throw new Error(data.error_description as string);
+ }
+ }
+ };
+}
\ No newline at end of file
diff --git a/packages/app/src/Pages/settings/wallet/index.tsx b/packages/app/src/Pages/settings/wallet/index.tsx
new file mode 100644
index 00000000..5716890d
--- /dev/null
+++ b/packages/app/src/Pages/settings/wallet/index.tsx
@@ -0,0 +1,34 @@
+import { RouteObject } from "react-router-dom";
+import WalletSettings from "../WalletSettings";
+import ConnectCashu from "./Cashu";
+import ConnectLNC from "./LNC";
+import ConnectLNDHub from "./LNDHub";
+import ConnectNostrWallet from "./NWC";
+import AlbyOAuth from "./Alby";
+
+export const WalletSettingsRoutes = [
+ {
+ path: "/settings/wallet",
+ element: ,
+ },
+ {
+ path: "/settings/wallet/lnc",
+ element: ,
+ },
+ {
+ path: "/settings/wallet/lndhub",
+ element: ,
+ },
+ {
+ path: "/settings/wallet/nwc",
+ element: ,
+ },
+ {
+ path: "/settings/wallet/cashu",
+ element: ,
+ },
+ {
+ path: "/settings/wallet/alby",
+ element: ,
+ }
+] as Array;
\ No newline at end of file