This commit is contained in:
parent
6951383045
commit
b41e8a919a
@ -91,7 +91,7 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
||||||
"@typescript-eslint/parser": "^6.1.0",
|
"@typescript-eslint/parser": "^6.1.0",
|
||||||
"@vitejs/plugin-react": "^4.2.0",
|
"@vitejs/plugin-react": "^4.2.0",
|
||||||
"@webbtc/webln-types": "^1.0.10",
|
"@webbtc/webln-types": "^2.1.0",
|
||||||
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
|
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"config": "^3.3.9",
|
"config": "^3.3.9",
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
import "./WalletPage.css";
|
import "./WalletPage.css";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { RouteObject, useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
|
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
|
||||||
|
|
||||||
import NoteTime from "@/Element/Event/NoteTime";
|
import NoteTime from "@/Element/Event/NoteTime";
|
||||||
import { WalletInvoice, Sats, WalletInfo, WalletInvoiceState, useWallet, LNWallet, Wallets } from "@/Wallet";
|
import { WalletInvoice, Sats, WalletInfo, WalletInvoiceState, useWallet, LNWallet, Wallets } from "@/Wallet";
|
||||||
import AsyncButton from "@/Element/Button/AsyncButton";
|
import AsyncButton from "@/Element/Button/AsyncButton";
|
||||||
import { unwrap } from "@/SnortUtils";
|
import { unwrap } from "@/SnortUtils";
|
||||||
import { WebLNWallet } from "@/Wallet/WebLN";
|
|
||||||
import Icon from "@/Icons/Icon";
|
import Icon from "@/Icons/Icon";
|
||||||
|
|
||||||
export const WalletRoutes: RouteObject[] = [
|
|
||||||
{
|
|
||||||
path: "/wallet",
|
|
||||||
element: <WalletPage />,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function WalletPage() {
|
export default function WalletPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
@ -33,10 +25,14 @@ export default function WalletPage() {
|
|||||||
try {
|
try {
|
||||||
const i = await wallet.getInfo();
|
const i = await wallet.getInfo();
|
||||||
setInfo(i);
|
setInfo(i);
|
||||||
const b = await wallet.getBalance();
|
if (wallet.canGetBalance()) {
|
||||||
setBalance(b as Sats);
|
const b = await wallet.getBalance();
|
||||||
const h = await wallet.getInvoices();
|
setBalance(b as Sats);
|
||||||
setHistory((h as WalletInvoice[]).sort((a, b) => b.timestamp - a.timestamp));
|
}
|
||||||
|
if (wallet.canGetInvoices()) {
|
||||||
|
const h = await wallet.getInvoices();
|
||||||
|
setHistory((h as WalletInvoice[]).sort((a, b) => b.timestamp - a.timestamp));
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
setError((e as Error).message);
|
setError((e as Error).message);
|
||||||
@ -62,11 +58,11 @@ export default function WalletPage() {
|
|||||||
function stateIcon(s: WalletInvoiceState) {
|
function stateIcon(s: WalletInvoiceState) {
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case WalletInvoiceState.Pending:
|
case WalletInvoiceState.Pending:
|
||||||
return <Icon name="clock" className="mr5" size={15} />;
|
return <Icon name="clock" size={15} />;
|
||||||
case WalletInvoiceState.Paid:
|
case WalletInvoiceState.Paid:
|
||||||
return <Icon name="check" className="mr5" size={15} />;
|
return <Icon name="check" size={15} />;
|
||||||
case WalletInvoiceState.Expired:
|
case WalletInvoiceState.Expired:
|
||||||
return <Icon name="close" className="mr5" size={15} />;
|
return <Icon name="close" size={15} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +128,7 @@ export default function WalletPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function walletHistory() {
|
function walletHistory() {
|
||||||
if (wallet instanceof WebLNWallet) return null;
|
if (!wallet?.canGetInvoices()) return;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -141,12 +137,12 @@ export default function WalletPage() {
|
|||||||
</h3>
|
</h3>
|
||||||
{history?.map(a => (
|
{history?.map(a => (
|
||||||
<div className="card flex wallet-history-item" key={a.timestamp}>
|
<div className="card flex wallet-history-item" key={a.timestamp}>
|
||||||
<div className="grow flex-col">
|
<div className="grow">
|
||||||
<NoteTime from={a.timestamp * 1000} fallback={formatMessage({ defaultMessage: "now", id: "kaaf1E" })} />
|
<NoteTime from={a.timestamp * 1000} fallback={formatMessage({ defaultMessage: "now", id: "kaaf1E" })} />
|
||||||
<div>{(a.memo ?? "").length === 0 ? <> </> : a.memo}</div>
|
<div>{(a.memo ?? "").length === 0 ? <> </> : a.memo}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`nowrap ${(() => {
|
className={`flex gap-2 items-center ${(() => {
|
||||||
switch (a.state) {
|
switch (a.state) {
|
||||||
case WalletInvoiceState.Paid:
|
case WalletInvoiceState.Paid:
|
||||||
return "success";
|
return "success";
|
||||||
@ -158,14 +154,16 @@ export default function WalletPage() {
|
|||||||
return "pending";
|
return "pending";
|
||||||
}
|
}
|
||||||
})()}`}>
|
})()}`}>
|
||||||
{stateIcon(a.state)}
|
<div>{stateIcon(a.state)}</div>
|
||||||
<FormattedMessage
|
<div>
|
||||||
defaultMessage="{amount} sats"
|
<FormattedMessage
|
||||||
id="vrTOHJ"
|
defaultMessage="{amount} sats"
|
||||||
values={{
|
id="vrTOHJ"
|
||||||
amount: <FormattedNumber value={a.amount / 1e3} />,
|
values={{
|
||||||
}}
|
amount: <FormattedNumber value={a.amount / 1e3} />,
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@ -174,7 +172,7 @@ export default function WalletPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function walletBalance() {
|
function walletBalance() {
|
||||||
if (wallet instanceof WebLNWallet) return null;
|
if (!wallet?.canGetBalance()) return;
|
||||||
return (
|
return (
|
||||||
<small>
|
<small>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@ -189,18 +187,13 @@ export default function WalletPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function walletInfo() {
|
function walletInfo() {
|
||||||
if (!wallet?.isReady()) return null;
|
if (!wallet?.isReady()) return;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="card">
|
<div className="p br b">
|
||||||
<h3>{info?.alias}</h3>
|
<div>{info?.alias}</div>
|
||||||
{walletBalance()}
|
{walletBalance()}
|
||||||
</div>
|
</div>
|
||||||
{/*<div className="flex wallet-buttons">
|
|
||||||
<AsyncButton onClick={createInvoice}>
|
|
||||||
<FormattedMessage defaultMessage="Receive" description="Receive sats by generating LN invoice" />
|
|
||||||
</AsyncButton>
|
|
||||||
</div>*/}
|
|
||||||
{walletHistory()}
|
{walletHistory()}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@ -208,8 +201,8 @@ export default function WalletPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="main-content p">
|
<div className="main-content p">
|
||||||
{error && <b className="error">{error}</b>}
|
|
||||||
{walletList()}
|
{walletList()}
|
||||||
|
{error && <b className="warning">{error}</b>}
|
||||||
{unlockWallet()}
|
{unlockWallet()}
|
||||||
{walletInfo()}
|
{walletInfo()}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import "./WalletSettings.css";
|
import "./WalletSettings.css";
|
||||||
import LndLogo from "@/lnd-logo.png";
|
import LndLogo from "@/lnd-logo.png";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { Link, RouteObject, useNavigate } from "react-router-dom";
|
import { RouteObject, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import BlueWallet from "@/Icons/BlueWallet";
|
import BlueWallet from "@/Icons/BlueWallet";
|
||||||
import ConnectLNC from "@/Pages/settings/wallet/LNC";
|
import ConnectLNC from "@/Pages/settings/wallet/LNC";
|
||||||
@ -10,16 +10,13 @@ import ConnectNostrWallet from "@/Pages/settings/wallet/NWC";
|
|||||||
import ConnectCashu from "@/Pages/settings/wallet/Cashu";
|
import ConnectCashu from "@/Pages/settings/wallet/Cashu";
|
||||||
|
|
||||||
import NostrIcon from "@/Icons/Nostrich";
|
import NostrIcon from "@/Icons/Nostrich";
|
||||||
|
import WalletPage from "../WalletPage";
|
||||||
|
|
||||||
const WalletSettings = () => {
|
const WalletSettings = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Link to="/wallet">
|
<WalletPage />
|
||||||
<button type="button">
|
|
||||||
<FormattedMessage defaultMessage="View Wallets" id="VvaJst" />
|
|
||||||
</button>
|
|
||||||
</Link>
|
|
||||||
<h3>
|
<h3>
|
||||||
<FormattedMessage defaultMessage="Connect Wallet" id="cg1VJ2" />
|
<FormattedMessage defaultMessage="Connect Wallet" id="cg1VJ2" />
|
||||||
</h3>
|
</h3>
|
||||||
|
@ -32,10 +32,18 @@ export class LNCWallet implements LNWallet {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
canAutoLogin(): boolean {
|
canAutoLogin() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canGetInvoices() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
canGetBalance() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
isReady(): boolean {
|
isReady(): boolean {
|
||||||
return this.#lnc.isReady;
|
return this.#lnc.isReady;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,15 @@ export default class LNDHubWallet implements LNWallet {
|
|||||||
return this.auth !== undefined;
|
return this.auth !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
canAutoLogin(): boolean {
|
canAutoLogin() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
canGetInvoices() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
canGetBalance() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,18 +114,21 @@ export default class LNDHubWallet implements LNWallet {
|
|||||||
|
|
||||||
async getInvoices(): Promise<WalletInvoice[]> {
|
async getInvoices(): Promise<WalletInvoice[]> {
|
||||||
const rsp = await this.getJson<UserInvoicesResponse[]>("GET", "/getuserinvoices");
|
const rsp = await this.getJson<UserInvoicesResponse[]>("GET", "/getuserinvoices");
|
||||||
return (rsp as UserInvoicesResponse[]).map(a => {
|
return (rsp as UserInvoicesResponse[])
|
||||||
const decodedInvoice = prToWalletInvoice(a.payment_request);
|
.sort((a, b) => (a.timestamp > b.timestamp ? -1 : 1))
|
||||||
if (!decodedInvoice) {
|
.slice(0, 50)
|
||||||
throw new WalletError(WalletErrorCode.InvalidInvoice, "Failed to parse invoice");
|
.map(a => {
|
||||||
}
|
const decodedInvoice = prToWalletInvoice(a.payment_request);
|
||||||
return {
|
if (!decodedInvoice) {
|
||||||
...decodedInvoice,
|
throw new WalletError(WalletErrorCode.InvalidInvoice, "Failed to parse invoice");
|
||||||
state: a.ispaid ? WalletInvoiceState.Paid : decodedInvoice.state,
|
}
|
||||||
paymentHash: a.payment_hash,
|
return {
|
||||||
memo: a.description,
|
...decodedInvoice,
|
||||||
} as WalletInvoice;
|
state: a.ispaid ? WalletInvoiceState.Paid : decodedInvoice.state,
|
||||||
});
|
paymentHash: a.payment_hash,
|
||||||
|
memo: a.description,
|
||||||
|
} as WalletInvoice;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getJson<T>(method: "GET" | "POST", path: string, body?: unknown): Promise<T> {
|
private async getJson<T>(method: "GET" | "POST", path: string, body?: unknown): Promise<T> {
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
import { Connection, EventKind, NostrEvent, EventBuilder, PrivateKeySigner } from "@snort/system";
|
import { Connection, EventKind, NostrEvent, EventBuilder, PrivateKeySigner } from "@snort/system";
|
||||||
import { LNWallet, WalletError, WalletErrorCode, WalletInfo, WalletInvoice, WalletInvoiceState } from "@/Wallet";
|
import {
|
||||||
|
InvoiceRequest,
|
||||||
|
LNWallet,
|
||||||
|
WalletError,
|
||||||
|
WalletErrorCode,
|
||||||
|
WalletInfo,
|
||||||
|
WalletInvoice,
|
||||||
|
WalletInvoiceState,
|
||||||
|
} from "@/Wallet";
|
||||||
import debug from "debug";
|
import debug from "debug";
|
||||||
|
import { dedupe } from "@snort/shared";
|
||||||
|
|
||||||
interface WalletConnectConfig {
|
interface WalletConnectConfig {
|
||||||
relayUrl: string;
|
relayUrl: string;
|
||||||
@ -30,10 +39,45 @@ interface WalletConnectResponse<T> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GetInfoResponse {
|
||||||
|
alias?: string;
|
||||||
|
color?: string;
|
||||||
|
pubkey?: string;
|
||||||
|
network?: string;
|
||||||
|
block_height?: number;
|
||||||
|
block_hash?: string;
|
||||||
|
methods?: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ListTransactionsResponse {
|
||||||
|
transactions: Array<{
|
||||||
|
type: "incoming" | "outgoing";
|
||||||
|
invoice: string;
|
||||||
|
description?: string;
|
||||||
|
description_hash?: string;
|
||||||
|
preimage?: string;
|
||||||
|
payment_hash?: string;
|
||||||
|
amount: number;
|
||||||
|
feed_paid: number;
|
||||||
|
settled_at?: number;
|
||||||
|
metadata?: object;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MakeInvoiceResponse {
|
||||||
|
invoice: string;
|
||||||
|
payment_hash: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefaultSupported = ["get_info", "pay_invoice"];
|
||||||
|
|
||||||
export class NostrConnectWallet implements LNWallet {
|
export class NostrConnectWallet implements LNWallet {
|
||||||
|
#log = debug("NWC");
|
||||||
#config: WalletConnectConfig;
|
#config: WalletConnectConfig;
|
||||||
#conn?: Connection;
|
#conn?: Connection;
|
||||||
#commandQueue: Map<string, QueueObj>;
|
#commandQueue: Map<string, QueueObj>;
|
||||||
|
#info?: WalletInfo;
|
||||||
|
#supported_methods: Array<string> = DefaultSupported;
|
||||||
|
|
||||||
constructor(cfg: string) {
|
constructor(cfg: string) {
|
||||||
this.#config = NostrConnectWallet.parseConfigUrl(cfg);
|
this.#config = NostrConnectWallet.parseConfigUrl(cfg);
|
||||||
@ -59,20 +103,43 @@ export class NostrConnectWallet implements LNWallet {
|
|||||||
|
|
||||||
async getInfo() {
|
async getInfo() {
|
||||||
await this.login();
|
await this.login();
|
||||||
return await new Promise<WalletInfo>((resolve, reject) => {
|
if (this.#info) return this.#info;
|
||||||
this.#commandQueue.set("info", {
|
|
||||||
resolve: (o: string) => {
|
const rsp = await this.#rpc<WalletConnectResponse<GetInfoResponse>>("get_info", {});
|
||||||
resolve({
|
if (!rsp.error) {
|
||||||
alias: "NWC",
|
this.#supported_methods = dedupe(["get_info", ...(rsp.result?.methods ?? DefaultSupported)]);
|
||||||
chains: o.split(" "),
|
this.#log("Supported methods: %o", this.#supported_methods);
|
||||||
} as WalletInfo);
|
const info = {
|
||||||
},
|
nodePubKey: rsp.result?.pubkey,
|
||||||
reject,
|
alias: rsp.result?.alias,
|
||||||
|
blockHeight: rsp.result?.block_height,
|
||||||
|
blockHash: rsp.result?.block_hash,
|
||||||
|
chains: rsp.result?.network ? [rsp.result.network] : undefined,
|
||||||
|
} as WalletInfo;
|
||||||
|
this.#info = info;
|
||||||
|
return info;
|
||||||
|
} else if (rsp.error.code === "NOT_IMPLEMENTED") {
|
||||||
|
// legacy get_info uses event kind 13_194
|
||||||
|
return await new Promise<WalletInfo>((resolve, reject) => {
|
||||||
|
this.#commandQueue.set("info", {
|
||||||
|
resolve: (o: string) => {
|
||||||
|
this.#supported_methods = dedupe(["get_info", ...o.split(",")]);
|
||||||
|
this.#log("Supported methods: %o", this.#supported_methods);
|
||||||
|
const info = {
|
||||||
|
alias: "NWC",
|
||||||
|
} as WalletInfo;
|
||||||
|
this.#info = info;
|
||||||
|
resolve(info);
|
||||||
|
},
|
||||||
|
reject,
|
||||||
|
});
|
||||||
|
this.#conn?.QueueReq(["REQ", "info", { kinds: [13194], limit: 1 }], () => {
|
||||||
|
// ignored
|
||||||
|
});
|
||||||
});
|
});
|
||||||
this.#conn?.QueueReq(["REQ", "info", { kinds: [13194], limit: 1 }], () => {
|
} else {
|
||||||
// ignored
|
throw new WalletError(WalletErrorCode.GeneralError, rsp.error.message);
|
||||||
});
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async login() {
|
async login() {
|
||||||
@ -100,11 +167,33 @@ export class NostrConnectWallet implements LNWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getBalance() {
|
async getBalance() {
|
||||||
return 0;
|
await this.login();
|
||||||
|
const rsp = await this.#rpc<WalletConnectResponse<{ balance: number }>>("get_balance", {});
|
||||||
|
if (!rsp.error) {
|
||||||
|
return (rsp.result?.balance ?? 0) / 1000;
|
||||||
|
} else {
|
||||||
|
throw new WalletError(WalletErrorCode.GeneralError, rsp.error.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createInvoice() {
|
async createInvoice(req: InvoiceRequest) {
|
||||||
return Promise.reject(new WalletError(WalletErrorCode.GeneralError, "Not implemented"));
|
await this.login();
|
||||||
|
const rsp = await this.#rpc<WalletConnectResponse<MakeInvoiceResponse>>("make_invoice", {
|
||||||
|
amount: req.amount * 1000,
|
||||||
|
description: req.memo,
|
||||||
|
expiry: req.expiry,
|
||||||
|
});
|
||||||
|
if (!rsp.error) {
|
||||||
|
return {
|
||||||
|
pr: rsp.result?.invoice,
|
||||||
|
paymentHash: rsp.result?.payment_hash,
|
||||||
|
memo: req.memo,
|
||||||
|
amount: req.amount * 1000,
|
||||||
|
state: WalletInvoiceState.Pending,
|
||||||
|
} as WalletInvoice;
|
||||||
|
} else {
|
||||||
|
throw new WalletError(WalletErrorCode.GeneralError, rsp.error.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async payInvoice(pr: string) {
|
async payInvoice(pr: string) {
|
||||||
@ -123,8 +212,38 @@ export class NostrConnectWallet implements LNWallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getInvoices() {
|
async getInvoices() {
|
||||||
return Promise.resolve([]);
|
await this.login();
|
||||||
|
const rsp = await this.#rpc<WalletConnectResponse<ListTransactionsResponse>>("list_transactions", {
|
||||||
|
limit: 50,
|
||||||
|
});
|
||||||
|
if (!rsp.error) {
|
||||||
|
return (
|
||||||
|
rsp.result?.transactions.map(
|
||||||
|
a =>
|
||||||
|
({
|
||||||
|
pr: a.invoice,
|
||||||
|
paymentHash: a.payment_hash,
|
||||||
|
memo: a.description,
|
||||||
|
amount: a.amount,
|
||||||
|
fees: a.feed_paid,
|
||||||
|
timestamp: a.settled_at,
|
||||||
|
preimage: a.preimage,
|
||||||
|
state: WalletInvoiceState.Paid,
|
||||||
|
}) as WalletInvoice,
|
||||||
|
) ?? []
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new WalletError(WalletErrorCode.GeneralError, rsp.error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canGetInvoices() {
|
||||||
|
return this.#supported_methods.includes("list_transactions");
|
||||||
|
}
|
||||||
|
|
||||||
|
canGetBalance() {
|
||||||
|
return this.#supported_methods.includes("get_balance");
|
||||||
}
|
}
|
||||||
|
|
||||||
async #onReply(sub: string, e: NostrEvent) {
|
async #onReply(sub: string, e: NostrEvent) {
|
||||||
@ -157,8 +276,19 @@ export class NostrConnectWallet implements LNWallet {
|
|||||||
this.#conn?.CloseReq(sub);
|
this.#conn?.CloseReq(sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
async #rpc<T>(method: string, params: Record<string, string>) {
|
async #rpc<T>(method: string, params: Record<string, string | number | undefined>) {
|
||||||
if (!this.#conn) throw new WalletError(WalletErrorCode.GeneralError, "Not implemented");
|
if (!this.#conn) throw new WalletError(WalletErrorCode.GeneralError, "Not implemented");
|
||||||
|
this.#log("> %o", { method, params });
|
||||||
|
if (!this.#supported_methods.includes(method)) {
|
||||||
|
const ret = {
|
||||||
|
error: {
|
||||||
|
code: "NOT_IMPLEMENTED",
|
||||||
|
message: `get_info claims the method "${method}" is not supported`,
|
||||||
|
},
|
||||||
|
} as T;
|
||||||
|
this.#log("< %o", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
const payload = JSON.stringify({
|
const payload = JSON.stringify({
|
||||||
method,
|
method,
|
||||||
@ -190,7 +320,7 @@ export class NostrConnectWallet implements LNWallet {
|
|||||||
this.#commandQueue.set(evCommand.id, {
|
this.#commandQueue.set(evCommand.id, {
|
||||||
resolve: async (o: string) => {
|
resolve: async (o: string) => {
|
||||||
const reply = JSON.parse(await signer.nip4Decrypt(o, this.#config.walletPubkey));
|
const reply = JSON.parse(await signer.nip4Decrypt(o, this.#config.walletPubkey));
|
||||||
debug("NWC")("%o", reply);
|
this.#log("< %o", reply);
|
||||||
resolve(reply);
|
resolve(reply);
|
||||||
},
|
},
|
||||||
reject,
|
reject,
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
WalletKind,
|
WalletKind,
|
||||||
WalletStore,
|
WalletStore,
|
||||||
} from "@/Wallet";
|
} from "@/Wallet";
|
||||||
import { barrierQueue, processWorkQueue, WorkQueueItem } from "@snort/shared";
|
import { barrierQueue, processWorkQueue, unwrap, WorkQueueItem } from "@snort/shared";
|
||||||
|
|
||||||
const WebLNQueue: Array<WorkQueueItem> = [];
|
const WebLNQueue: Array<WorkQueueItem> = [];
|
||||||
processWorkQueue(WebLNQueue);
|
processWorkQueue(WebLNQueue);
|
||||||
@ -75,8 +75,12 @@ export class WebLNWallet implements LNWallet {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBalance(): Promise<Sats> {
|
async getBalance(): Promise<Sats> {
|
||||||
return Promise.resolve(0);
|
if (window.webln?.getBalance) {
|
||||||
|
const rsp = await barrierQueue(WebLNQueue, async () => await unwrap(window.webln?.getBalance).call(window.webln));
|
||||||
|
return rsp.balance;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createInvoice(req: InvoiceRequest): Promise<WalletInvoice> {
|
async createInvoice(req: InvoiceRequest): Promise<WalletInvoice> {
|
||||||
@ -124,4 +128,12 @@ export class WebLNWallet implements LNWallet {
|
|||||||
getInvoices(): Promise<WalletInvoice[]> {
|
getInvoices(): Promise<WalletInvoice[]> {
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canGetInvoices() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
canGetBalance() {
|
||||||
|
return window.webln?.getBalance !== undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,6 @@ export type MilliSats = number;
|
|||||||
|
|
||||||
export interface LNWallet {
|
export interface LNWallet {
|
||||||
isReady(): boolean;
|
isReady(): boolean;
|
||||||
canAutoLogin(): boolean;
|
|
||||||
getInfo: () => Promise<WalletInfo>;
|
getInfo: () => Promise<WalletInfo>;
|
||||||
login: (password?: string) => Promise<boolean>;
|
login: (password?: string) => Promise<boolean>;
|
||||||
close: () => Promise<boolean>;
|
close: () => Promise<boolean>;
|
||||||
@ -109,6 +108,10 @@ export interface LNWallet {
|
|||||||
createInvoice: (req: InvoiceRequest) => Promise<WalletInvoice>;
|
createInvoice: (req: InvoiceRequest) => Promise<WalletInvoice>;
|
||||||
payInvoice: (pr: string) => Promise<WalletInvoice>;
|
payInvoice: (pr: string) => Promise<WalletInvoice>;
|
||||||
getInvoices: () => Promise<WalletInvoice[]>;
|
getInvoices: () => Promise<WalletInvoice[]>;
|
||||||
|
|
||||||
|
canAutoLogin: () => boolean;
|
||||||
|
canGetInvoices: () => boolean;
|
||||||
|
canGetBalance: () => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WalletConfig {
|
export interface WalletConfig {
|
||||||
|
@ -39,7 +39,6 @@ import MessagesPage from "@/Pages/Messages/MessagesPage";
|
|||||||
import DonatePage from "@/Pages/DonatePage";
|
import DonatePage from "@/Pages/DonatePage";
|
||||||
import SearchPage from "@/Pages/SearchPage";
|
import SearchPage from "@/Pages/SearchPage";
|
||||||
import HelpPage from "@/Pages/HelpPage";
|
import HelpPage from "@/Pages/HelpPage";
|
||||||
import { WalletRoutes } from "@/Pages/WalletPage";
|
|
||||||
import NostrLinkHandler from "@/Pages/NostrLinkHandler";
|
import NostrLinkHandler from "@/Pages/NostrLinkHandler";
|
||||||
import { ThreadRoute } from "@/Element/Event/Thread";
|
import { ThreadRoute } from "@/Element/Event/Thread";
|
||||||
import { SubscribeRoutes } from "@/Pages/subscribe";
|
import { SubscribeRoutes } from "@/Pages/subscribe";
|
||||||
@ -275,7 +274,6 @@ const mainRoutes = [
|
|||||||
element: <NetworkGraph />,
|
element: <NetworkGraph />,
|
||||||
},
|
},
|
||||||
...OnboardingRoutes,
|
...OnboardingRoutes,
|
||||||
...WalletRoutes,
|
|
||||||
] as Array<RouteObject>;
|
] as Array<RouteObject>;
|
||||||
|
|
||||||
if (CONFIG.features.zapPool) {
|
if (CONFIG.features.zapPool) {
|
||||||
|
@ -894,9 +894,6 @@
|
|||||||
"VnXp8Z": {
|
"VnXp8Z": {
|
||||||
"defaultMessage": "Avatar"
|
"defaultMessage": "Avatar"
|
||||||
},
|
},
|
||||||
"VvaJst": {
|
|
||||||
"defaultMessage": "View Wallets"
|
|
||||||
},
|
|
||||||
"W1yoZY": {
|
"W1yoZY": {
|
||||||
"defaultMessage": "It looks like you dont have any subscriptions, you can get one {link}"
|
"defaultMessage": "It looks like you dont have any subscriptions, you can get one {link}"
|
||||||
},
|
},
|
||||||
|
@ -294,7 +294,6 @@
|
|||||||
"VfhYxG": "To see a full list of changes you can view the changelog {here}",
|
"VfhYxG": "To see a full list of changes you can view the changelog {here}",
|
||||||
"VlJkSk": "{n} muted",
|
"VlJkSk": "{n} muted",
|
||||||
"VnXp8Z": "Avatar",
|
"VnXp8Z": "Avatar",
|
||||||
"VvaJst": "View Wallets",
|
|
||||||
"W1yoZY": "It looks like you dont have any subscriptions, you can get one {link}",
|
"W1yoZY": "It looks like you dont have any subscriptions, you can get one {link}",
|
||||||
"W2PiAr": "{n} Blocked",
|
"W2PiAr": "{n} Blocked",
|
||||||
"W9355R": "Unmute",
|
"W9355R": "Unmute",
|
||||||
|
10
yarn.lock
10
yarn.lock
@ -2911,7 +2911,7 @@ __metadata:
|
|||||||
"@uidotdev/usehooks": ^2.4.1
|
"@uidotdev/usehooks": ^2.4.1
|
||||||
"@vitejs/plugin-react": ^4.2.0
|
"@vitejs/plugin-react": ^4.2.0
|
||||||
"@void-cat/api": ^1.0.10
|
"@void-cat/api": ^1.0.10
|
||||||
"@webbtc/webln-types": ^1.0.10
|
"@webbtc/webln-types": ^2.1.0
|
||||||
"@webscopeio/react-textarea-autocomplete": ^4.9.2
|
"@webscopeio/react-textarea-autocomplete": ^4.9.2
|
||||||
autoprefixer: ^10.4.16
|
autoprefixer: ^10.4.16
|
||||||
classnames: ^2.3.2
|
classnames: ^2.3.2
|
||||||
@ -3961,10 +3961,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@webbtc/webln-types@npm:^1.0.10":
|
"@webbtc/webln-types@npm:^2.1.0":
|
||||||
version: 1.0.14
|
version: 2.1.0
|
||||||
resolution: "@webbtc/webln-types@npm:1.0.14"
|
resolution: "@webbtc/webln-types@npm:2.1.0"
|
||||||
checksum: eaa363bf3a9c278be51c93487904c04518e8812d97449d8d7866089aae74756451a48245a31b1a0fd591bc4798a96a29516ad395b8828c9f2af920cf65a305ac
|
checksum: 71c8ae3fc4e163dfa2271f19216b603f53a6910e65fdb115b1920ef9be4b7fa990d9c1c644900a7e88c69e8a8a8cc2e273aa490903e6064e2f296498cdca53ff
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user