allow purchasing time with lightning directly not just cashu (fix #9)
This commit is contained in:
parent
77a9a6842b
commit
88d9515ba6
3 changed files with 67 additions and 1 deletions
|
@ -26,6 +26,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@arx/utils": "git+ssh://git@git.arx-ccn.com:222/Arx/ts-utils#03163e9f4a07b011a28a8f97c90852ecfc806ddd",
|
"@arx/utils": "git+ssh://git@git.arx-ccn.com:222/Arx/ts-utils#03163e9f4a07b011a28a8f97c90852ecfc806ddd",
|
||||||
|
"@cashu/cashu-ts": "^2.1.0",
|
||||||
"@gandlaf21/bc-ur": "^1.1.12",
|
"@gandlaf21/bc-ur": "^1.1.12",
|
||||||
"@nostr-dev-kit/ndk": "^2.10.7",
|
"@nostr-dev-kit/ndk": "^2.10.7",
|
||||||
"@nostr-dev-kit/ndk-cache-dexie": "^2.5.8",
|
"@nostr-dev-kit/ndk-cache-dexie": "^2.5.8",
|
||||||
|
|
|
@ -37,7 +37,7 @@ button, .button {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
input[type="text"], input[type="password"] {
|
input[type="text"], input[type="number"], input[type="password"] {
|
||||||
background: var(--editor-bg);
|
background: var(--editor-bg);
|
||||||
border: 1px solid var(--input-border);
|
border: 1px solid var(--input-border);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
import { TokenInfoWithMailSubscriptionDuration } from '@arx/utils';
|
import { TokenInfoWithMailSubscriptionDuration } from '@arx/utils';
|
||||||
import TimeCountdown from '../../components/TimeCountdown.svelte';
|
import TimeCountdown from '../../components/TimeCountdown.svelte';
|
||||||
import { ndk } from '$lib/stores.svelte';
|
import { ndk } from '$lib/stores.svelte';
|
||||||
|
import { CashuMint, CashuWallet, getEncodedTokenV4, MintQuoteState } from '@cashu/cashu-ts';
|
||||||
|
import type { MintQuoteResponse } from '@cashu/cashu-ts';
|
||||||
|
import Dialog from '../../components/Dialog.svelte';
|
||||||
|
import * as qr from 'qrcode';
|
||||||
|
|
||||||
let { onReloadNeeded } = $props<{
|
let { onReloadNeeded } = $props<{
|
||||||
onReloadNeeded: () => void;
|
onReloadNeeded: () => void;
|
||||||
|
@ -35,6 +39,44 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let buyingWithLightning = $state(false);
|
||||||
|
let lightningAmount = $state(21);
|
||||||
|
let invoice = $state('');
|
||||||
|
let invoiceQR = $state('');
|
||||||
|
let mintQuote = $state<MintQuoteResponse | null>(null);
|
||||||
|
|
||||||
|
const mint = new CashuMint('https://mint.minibits.cash/Bitcoin');
|
||||||
|
const wallet = new CashuWallet(mint);
|
||||||
|
|
||||||
|
async function buyWithLightning() {
|
||||||
|
if (tokenInfo) return;
|
||||||
|
if(!mintQuote) return;
|
||||||
|
const mintQuoteChecked = await wallet.checkMintQuote(mintQuote.quote);
|
||||||
|
if (mintQuoteChecked.state === MintQuoteState.PAID) {
|
||||||
|
const proofs = await wallet.mintProofs(lightningAmount, mintQuote.quote);
|
||||||
|
cashuTokenForBuy = getEncodedTokenV4({ mint: mint.mintUrl, proofs: proofs });
|
||||||
|
buyingWithLightning = false;
|
||||||
|
invoice = '';
|
||||||
|
invoiceQR = '';
|
||||||
|
mintQuote = null;
|
||||||
|
try {
|
||||||
|
tokenInfo = new TokenInfoWithMailSubscriptionDuration(cashuTokenForBuy);
|
||||||
|
tokenInfoError = '';
|
||||||
|
} catch (e) {
|
||||||
|
tokenInfoError = (e as Error).message;
|
||||||
|
}
|
||||||
|
buyTime();
|
||||||
|
} else
|
||||||
|
alert('Invoice not paid yet')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateInvoice() {
|
||||||
|
await wallet.loadMint();
|
||||||
|
mintQuote = await wallet.createMintQuote(lightningAmount);
|
||||||
|
invoice = mintQuote.request;
|
||||||
|
invoiceQR = await qr.toDataURL(invoice);
|
||||||
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
try {
|
try {
|
||||||
tokenInfo = new TokenInfoWithMailSubscriptionDuration(cashuTokenForBuy);
|
tokenInfo = new TokenInfoWithMailSubscriptionDuration(cashuTokenForBuy);
|
||||||
|
@ -45,6 +87,28 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<Dialog bind:open={buyingWithLightning}>
|
||||||
|
<div class="section-title">
|
||||||
|
<h3>Buy time with lightning</h3>
|
||||||
|
<button class="close-button" onclick={() => (buyingWithLightning = false)}>Close</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if !invoice}
|
||||||
|
<p>Enter the amount of time you want to buy (min 21 sats, 210 sats = 1 day):</p>
|
||||||
|
|
||||||
|
<input bind:value={lightningAmount} min="21" placeholder="Enter amount" type="number" />
|
||||||
|
|
||||||
|
<button onclick={generateInvoice}>Generate Invoice</button>
|
||||||
|
{:else}
|
||||||
|
<div style="align-items: center; display: flex; flex-direction: column;">
|
||||||
|
<img src={invoiceQR} alt="Lightning Invoice" />
|
||||||
|
<input disabled value={invoice} type="text" />
|
||||||
|
<p>After payment, click the button below to add the time to your account.</p>
|
||||||
|
<button onclick={buyWithLightning}>Add time</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
{#if cashuTokenForBuy !== ''}
|
{#if cashuTokenForBuy !== ''}
|
||||||
{#if tokenInfoError}
|
{#if tokenInfoError}
|
||||||
<p class="error">{tokenInfoError}</p>
|
<p class="error">{tokenInfoError}</p>
|
||||||
|
@ -56,6 +120,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<input bind:value={cashuTokenForBuy} placeholder="Enter cashu token" type="text" />
|
<input bind:value={cashuTokenForBuy} placeholder="Enter cashu token" type="text" />
|
||||||
|
<button onclick={() => buyTimeForNpub.trim() ? buyingWithLightning = true : alert('Please enter a valid npub first')}>Or click here for lightning</button>
|
||||||
<h4>Buy for:</h4>
|
<h4>Buy for:</h4>
|
||||||
<input bind:value={buyTimeForNpub} placeholder="Enter npub" type="text" />
|
<input bind:value={buyTimeForNpub} placeholder="Enter npub" type="text" />
|
||||||
<button onclick={() => (buyTimeForNpub = $ndk.activeUser.npub)}>Set to your own</button>
|
<button onclick={() => (buyTimeForNpub = $ndk.activeUser.npub)}>Set to your own</button>
|
||||||
|
|
Loading…
Reference in a new issue