diff --git a/package.json b/package.json index 41494cda..8cd96080 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,9 @@ ], "onlyBuiltDependencies": [ "sharp" - ] + ], + "overrides": { + "sharp": "0.35.0-rc.0" + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2014aaac..94d8fcc3 100644 Binary files a/pnpm-lock.yaml and b/pnpm-lock.yaml differ diff --git a/src/app/components/WalletPay.svelte b/src/app/components/WalletPay.svelte index 53699f77..57b48307 100644 --- a/src/app/components/WalletPay.svelte +++ b/src/app/components/WalletPay.svelte @@ -14,6 +14,7 @@ import ModalTitle from "@lib/components/ModalTitle.svelte" import ModalSubtitle from "@lib/components/ModalSubtitle.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" + import {errorMessage} from "@lib/util" import {payInvoice} from "@app/core/commands" import {pushToast} from "@app/util/toast" import {clearModals} from "@app/util/modal" @@ -29,14 +30,18 @@ loading = true try { - await payInvoice(invoice!.paymentRequest, sats * 1000) + if (hasAmount) { + await payInvoice(invoice!.paymentRequest) + } else { + await payInvoice(invoice!.paymentRequest, sats * 1000) + } pushToast({message: `Payment sent!`}) clearModals() } catch (e) { console.error(e) - const message = String(e).replace(/^.*Error: /, "") + const message = errorMessage(e) pushToast({ theme: "error", @@ -50,6 +55,7 @@ let loading = $state(false) let invoice: Invoice | undefined = $state() let sats = $state(0) + const hasAmount = $derived((invoice?.satoshi ?? 0) > 0) @@ -60,7 +66,7 @@ {#if invoice}
- {#if $session?.wallet?.type === "webln" && invoice.satoshi === 0} + {#if $session?.wallet?.type === "webln" && !hasAmount}

Uh oh! It looks like your current wallet doesn't support invoices without an amount. See if you can get a lightning invoice with a pre-set amount. @@ -101,7 +107,13 @@ Go back - + {#if invoice} + + {:else} + + {/if} + + diff --git a/src/app/components/Zap.svelte b/src/app/components/Zap.svelte index e842a4a2..62fd3e77 100644 --- a/src/app/components/Zap.svelte +++ b/src/app/components/Zap.svelte @@ -17,6 +17,7 @@ import ModalSubtitle from "@lib/components/ModalSubtitle.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" import EmojiButton from "@lib/components/EmojiButton.svelte" + import {errorMessage} from "@lib/util" import ProfileLink from "@app/components/ProfileLink.svelte" import {payInvoice} from "@app/core/commands" import {pushToast} from "@app/util/toast" @@ -85,7 +86,7 @@ } catch (e) { console.error(e) - const message = String(e).replace(/^.*Error: /, "") + const message = errorMessage(e) pushToast({ theme: "error", diff --git a/src/app/core/commands.ts b/src/app/core/commands.ts index a169d6a3..4fbb9c55 100644 --- a/src/app/core/commands.ts +++ b/src/app/core/commands.ts @@ -425,6 +425,22 @@ export const publishLeaveRequest = (params: LeaveRequestParams) => export const getWebLn = () => (window as any).webln +export const getNwcClient = () => { + const $session = session.get() + + if (!$session?.wallet || $session.wallet.type !== "nwc") { + throw new Error("No NWC wallet is connected") + } + + const {info} = $session.wallet + + if (info.nostrWalletConnectUrl) { + return new nwc.NWCClient({nostrWalletConnectUrl: info.nostrWalletConnectUrl}) + } + + return new nwc.NWCClient(info) +} + export const payInvoice = async (invoice: string, msats?: number) => { const $session = session.get() @@ -435,7 +451,7 @@ export const payInvoice = async (invoice: string, msats?: number) => { if ($session.wallet.type === "nwc") { const params: {invoice: string; amount?: number} = {invoice} if (msats) params.amount = msats - return new nwc.NWCClient($session.wallet.info).payInvoice(params) + return getNwcClient().payInvoice(params) } else if ($session.wallet.type === "webln") { if (msats) throw new Error("Unable to pay zero invoices with webln") return getWebLn() @@ -444,6 +460,67 @@ export const payInvoice = async (invoice: string, msats?: number) => { } } +export type CreateInvoiceParams = { + sats: number + description?: string +} + +export const createInvoice = async ({ + sats, + description = "Receive via lightning", +}: CreateInvoiceParams) => { + const $session = session.get() + + if (!$session?.wallet) { + throw new Error("No wallet is connected") + } + + const satAmount = Math.floor(sats) + + if (!Number.isFinite(satAmount) || satAmount <= 0) { + throw new Error("Invalid satoshi amount") + } + + if ($session.wallet.type === "nwc") { + const createdInvoice = await getNwcClient().makeInvoice({ + amount: satAmount * 1000, + description, + }) + + if (!createdInvoice.invoice) { + throw new Error("NWC wallet failed to return an invoice") + } + + return createdInvoice.invoice + } + + if ($session.wallet.type === "webln") { + const webLn = getWebLn() + + if (!webLn) { + throw new Error("WebLN not available") + } + + await webLn.enable() + + const response = await webLn.makeInvoice({ + amount: satAmount, + defaultMemo: description, + }) + + const paymentRequest = + typeof response === "string" ? response : response?.paymentRequest || response?.pr || "" + + if (!paymentRequest) { + throw new Error("Invalid payment request returned from WebLN") + } + + return paymentRequest + } + + throw new Error("Unsupported wallet type") +} + // File upload export const normalizeBlossomUrl = (url: string) => normalizeUrl(url.replace(/^ws/, "http")) diff --git a/src/lib/util.ts b/src/lib/util.ts index ab23de01..a1ae8d5b 100644 --- a/src/lib/util.ts +++ b/src/lib/util.ts @@ -17,6 +17,8 @@ export const daysBetween = (start: number, end: number) => [...range(start, end, export const ucFirst = (s: string) => s.slice(0, 1).toUpperCase() + s.slice(1) +export const errorMessage = (err: unknown) => String(err).replace(/^.*Error: /, "") + export const buildUrl = (base: string | URL, ...pathname: string[]) => { const url = new URL(base) diff --git a/src/routes/settings/wallet/+page.svelte b/src/routes/settings/wallet/+page.svelte index 4af6442a..fed15a08 100644 --- a/src/routes/settings/wallet/+page.svelte +++ b/src/routes/settings/wallet/+page.svelte @@ -3,10 +3,12 @@ import {LOCALE} from "@welshman/lib" import {displayRelayUrl, isNWCWallet, fromMsats} from "@welshman/util" import {session, pubkey, profilesByPubkey} from "@welshman/app" - import Bolt from "@assets/icons/bolt.svg?dataurl" + import DownloadMinimalistic from "@assets/icons/download-minimalistic.svg?dataurl" + import UploadMinimalistic from "@assets/icons/upload-minimalistic.svg?dataurl" import Icon from "@lib/components/Icon.svelte" import Button from "@lib/components/Button.svelte" import WalletPay from "@app/components/WalletPay.svelte" + import WalletReceive from "@app/components/WalletReceive.svelte" import WalletConnect from "@app/components/WalletConnect.svelte" import WalletDisconnect from "@app/components/WalletDisconnect.svelte" import WalletUpdateReceivingAddress from "@app/components/WalletUpdateReceivingAddress.svelte" @@ -31,6 +33,13 @@ ) const pay = () => pushModal(WalletPay) + const receive = () => { + if ($session?.wallet) { + pushModal(WalletReceive) + } else { + pushModal(WalletConnect) + } + }

@@ -94,10 +103,24 @@

{/if} - +
+ +
+ + +
+
{:else}

No wallet connected

{/if} @@ -122,10 +145,4 @@
{/if} -
- -