2021-07-17 13:44:07 +03:00
|
|
|
|
<script>
|
|
|
|
|
|
|
|
|
|
export let name;
|
|
|
|
|
|
|
|
|
|
import SiteHead from './SiteHead.svelte';
|
|
|
|
|
import SiteCard from './SiteCard.svelte';
|
|
|
|
|
import SiteDeck from './SiteDeck.svelte';
|
|
|
|
|
import InputMask from './InputMask.svelte';
|
2021-09-24 05:28:10 +03:00
|
|
|
|
|
2021-07-17 13:44:07 +03:00
|
|
|
|
import payways from './payways.js';
|
2022-01-07 17:51:29 +03:00
|
|
|
|
|
2021-07-17 13:44:07 +03:00
|
|
|
|
import QR from './QR.svelte';
|
|
|
|
|
|
|
|
|
|
import CTC from './CTC.svelte';
|
|
|
|
|
import Tipped from './Tipped.svelte';
|
|
|
|
|
|
|
|
|
|
import { bech32 } from 'bech32'
|
|
|
|
|
import UTF8 from 'utf-8'
|
|
|
|
|
|
|
|
|
|
import PayFlow from './PayFlow.svelte';
|
2022-01-07 17:51:29 +03:00
|
|
|
|
import { ecEncrypt } from './ecies.js';
|
|
|
|
|
|
2021-07-17 13:44:07 +03:00
|
|
|
|
let payway = payways[0];
|
2021-09-24 05:28:10 +03:00
|
|
|
|
|
2021-07-17 13:44:07 +03:00
|
|
|
|
setTimeout(()=>{
|
|
|
|
|
payway = payways[0];
|
|
|
|
|
accounts[inputId]=null;
|
|
|
|
|
},0);
|
|
|
|
|
|
|
|
|
|
let inputId;
|
|
|
|
|
let amountMask;
|
|
|
|
|
let realAmount;
|
2022-01-07 17:51:29 +03:00
|
|
|
|
let extAccount;
|
|
|
|
|
let briefAccount;
|
|
|
|
|
let encrypt = false;
|
2021-07-17 13:44:07 +03:00
|
|
|
|
|
|
|
|
|
$: inputId = payway.iid||payway.id;
|
2022-01-07 17:51:29 +03:00
|
|
|
|
$: accountReady = accountComplete && accounts[inputId]
|
2021-07-17 13:44:07 +03:00
|
|
|
|
$: amountMask = {
|
|
|
|
|
mask: Number, scale:2,
|
|
|
|
|
min: payway.min, max:payway.max,
|
|
|
|
|
radix:".",mapToRadix:[","],
|
|
|
|
|
padFractionalZeros: true,
|
|
|
|
|
normalizeZeros: true}
|
|
|
|
|
|
|
|
|
|
$: realAmount = amounts[payway.id] && (
|
|
|
|
|
Math.max(Math.min(amounts[payway.id], payway.max),payway.min))
|
2022-01-07 17:51:29 +03:00
|
|
|
|
|
|
|
|
|
$: extAccount = accountReady ? (encrypt? "0g" + ecEncrypt(accounts[inputId].padEnd(8)): accounts[inputId]):"";
|
|
|
|
|
|
|
|
|
|
$: briefAccount = extAccount ? (encrypt ? extAccount.slice(0,28)+"…" : extAccount):""
|
2021-07-17 13:44:07 +03:00
|
|
|
|
|
|
|
|
|
function genAutoMemo(payway,account,amount) {
|
|
|
|
|
if (!account)
|
|
|
|
|
return "...automatic";
|
|
|
|
|
if (amount)
|
|
|
|
|
amount = parseFloat(amount)
|
|
|
|
|
let sum = amount?
|
|
|
|
|
amount.toFixed(amount===Math.round(amount)?0:2)
|
|
|
|
|
+ " " + payway.currency.toLowerCase() : "some sats";
|
|
|
|
|
return sum + " to " + payway.id + " " + account;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let autoMemo;
|
2022-01-07 17:51:29 +03:00
|
|
|
|
$: autoMemo = genAutoMemo(payway, briefAccount, realAmount)
|
2021-09-24 05:28:10 +03:00
|
|
|
|
let lightningAddress;
|
2022-01-07 17:51:29 +03:00
|
|
|
|
$: lightningAddress = accountComplete ? genAddress(payway, extAccount, realAmount):""
|
2021-07-17 13:44:07 +03:00
|
|
|
|
|
|
|
|
|
function lnurlEncode(url) {
|
2022-01-07 17:51:29 +03:00
|
|
|
|
return bech32.encode("LNURL", bech32.toWords(UTF8.setBytesFromString(url)),2048)
|
2021-07-17 13:44:07 +03:00
|
|
|
|
}
|
2021-09-24 05:28:10 +03:00
|
|
|
|
|
2021-07-17 13:44:07 +03:00
|
|
|
|
function toHexString(byteArray) {
|
|
|
|
|
return Array.from(byteArray, function(byte) {
|
|
|
|
|
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
|
|
|
|
|
}).join('')
|
|
|
|
|
}
|
2022-01-07 17:51:29 +03:00
|
|
|
|
|
2021-09-24 05:28:10 +03:00
|
|
|
|
function genAddress(payway,account,amount) {
|
|
|
|
|
if (!account || !payway)
|
|
|
|
|
return ""
|
|
|
|
|
const prefix = amount?
|
|
|
|
|
((amount == Math.floor(amount)? ""+amount:
|
|
|
|
|
amount.toFixed(2))+payway.currency.toLowerCase()+"-"):""
|
|
|
|
|
if (account[0]=='+')
|
|
|
|
|
account=account.slice(1)
|
|
|
|
|
return prefix + account + "@" + payway.id + ".lnurl-pay.me"
|
|
|
|
|
}
|
2021-07-17 13:44:07 +03:00
|
|
|
|
|
2022-01-07 17:51:29 +03:00
|
|
|
|
function genLNURL(payway,account,amount,memo,isEncrypted) {
|
2021-07-17 13:44:07 +03:00
|
|
|
|
let params = new URLSearchParams();
|
|
|
|
|
params.set("mtg","pay");
|
|
|
|
|
params.set("p",payway.id);
|
2022-01-07 17:51:29 +03:00
|
|
|
|
// don't hex-encode bech32-encoded account
|
|
|
|
|
params.set("acc",isEncrypted? account: toHexString(UTF8.setBytesFromString(account)))
|
2021-07-17 13:44:07 +03:00
|
|
|
|
params.set("v","1")
|
|
|
|
|
if (amount) {
|
|
|
|
|
params.set(payway.currency.toLowerCase(),amount)
|
|
|
|
|
}
|
|
|
|
|
if (memo) {
|
|
|
|
|
params.set("m",toHexString(UTF8.setBytesFromString(memo)))
|
|
|
|
|
}
|
|
|
|
|
return lnurlEncode("https://lnurl-pay.me/pay?"+params.toString()).toUpperCase()
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-07 17:51:29 +03:00
|
|
|
|
|
2021-07-17 13:44:07 +03:00
|
|
|
|
let accounts = {};
|
|
|
|
|
let amounts = {};
|
|
|
|
|
let memo;
|
|
|
|
|
|
|
|
|
|
let lnurl;
|
|
|
|
|
|
|
|
|
|
$: lnurl = accountComplete ?
|
2022-01-07 17:51:29 +03:00
|
|
|
|
genLNURL(payway, extAccount, realAmount, memo, encrypt) : "";
|
2021-07-17 13:44:07 +03:00
|
|
|
|
|
|
|
|
|
const curr = {
|
|
|
|
|
"UAH":"₴",
|
|
|
|
|
"RUB":"₽",
|
|
|
|
|
"USD":"$",
|
|
|
|
|
"KZT":"₸",
|
2021-07-20 00:21:42 +03:00
|
|
|
|
"NGN":"₦",
|
2021-08-12 20:57:30 +03:00
|
|
|
|
"ZAR":"R",
|
|
|
|
|
"GHS":"₵",
|
2021-08-17 01:01:49 +03:00
|
|
|
|
"AFN":"Af",
|
2021-07-17 13:44:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let accountComplete = false;
|
|
|
|
|
|
|
|
|
|
const canShare = !!navigator.share;
|
|
|
|
|
|
|
|
|
|
let getInvoiceFor;
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<SiteHead/>
|
|
|
|
|
|
|
|
|
|
<SiteDeck>
|
|
|
|
|
<SiteCard>
|
|
|
|
|
<p class="form-text">Fill in everything to get your lnurl-pay link</p>
|
|
|
|
|
<label class="form-label mb-3">Payment direction
|
|
|
|
|
<select class="form-select" autofocus bind:value="{payway}">
|
|
|
|
|
{#each payways as payway}
|
|
|
|
|
<option value="{payway}">{payway.name}</option>
|
|
|
|
|
{/each}
|
|
|
|
|
</select>
|
|
|
|
|
</label>
|
|
|
|
|
|
|
|
|
|
{#key payway}
|
|
|
|
|
<label class="form-label mb-3">{payway.acc}
|
2022-01-07 17:51:29 +03:00
|
|
|
|
<div class="input-group">
|
|
|
|
|
<InputMask
|
|
|
|
|
unmask
|
|
|
|
|
bind:value={accounts[inputId]}
|
|
|
|
|
bind:isComplete={accountComplete}
|
|
|
|
|
imask={payway.imask||{mask:/.*/}}
|
|
|
|
|
autocomplete={payway.autocomplete}
|
|
|
|
|
inputmode={payway.inputmode||"numeric"}
|
|
|
|
|
placeholder={payway.placeholder}
|
|
|
|
|
class="form-control"/>
|
|
|
|
|
<span class="input-group-text">
|
|
|
|
|
<div class="form-check-inline form-check input-group-prepend">
|
|
|
|
|
<input class="form-check-input" type="checkbox" id="cbEncrypt"
|
|
|
|
|
bind:checked={encrypt}>
|
|
|
|
|
<label class="form-check-label" for="cbEncrypt">
|
|
|
|
|
Encrypt
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
2021-07-17 13:44:07 +03:00
|
|
|
|
</label>
|
|
|
|
|
<label class="form-label mb-3">
|
|
|
|
|
Amount: {payway.currency} {payway.min} – {payway.max}
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
<div class="input-group-prepend">
|
|
|
|
|
<span class="input-group-text">{curr[payway.currency]}</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<InputMask bind:value={amounts[payway.id]}
|
|
|
|
|
unmask
|
|
|
|
|
imask={amountMask}
|
|
|
|
|
placeholder="determined by payer"
|
|
|
|
|
inputmode={"numeric"}
|
|
|
|
|
class="form-control"/>
|
|
|
|
|
<button class="btn btn-outline-secondary"
|
|
|
|
|
type="button"
|
|
|
|
|
on:click={()=> amounts[payway.id]=payway.min.toString()}>Min
|
|
|
|
|
</button>
|
|
|
|
|
<button class="btn btn-outline-secondary"
|
|
|
|
|
type="button"
|
|
|
|
|
on:click={()=> amounts[payway.id]=payway.max.toString()}>Max
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</label>
|
|
|
|
|
{/key}
|
|
|
|
|
<label class="form-label mb-3">Lnurl MEMO
|
|
|
|
|
<input bind:value={memo} placeholder="{autoMemo}"
|
|
|
|
|
class="form-control"/>
|
|
|
|
|
</label>
|
|
|
|
|
</SiteCard>
|
|
|
|
|
<SiteCard>
|
|
|
|
|
{#if lnurl}
|
|
|
|
|
<CTC let:id let:action force text={lnurl}>
|
2021-09-24 05:33:14 +03:00
|
|
|
|
<div class="form-text user-select-all mb-0 mt-2"
|
2021-07-17 13:44:07 +03:00
|
|
|
|
style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"
|
|
|
|
|
on:click={action} id={id}>{lnurl}
|
|
|
|
|
</div>
|
|
|
|
|
</CTC>
|
|
|
|
|
{:else}
|
|
|
|
|
<div class="form-text mb-2 mt-2">Expecting: {payway.acc.toLowerCase()}</div>
|
|
|
|
|
{/if}
|
2021-09-24 05:50:20 +03:00
|
|
|
|
<div class="d-flex justify-content-center align-items-stretch m-1"
|
2021-09-24 05:28:10 +03:00
|
|
|
|
class:invisible={!lnurl}>
|
2021-09-24 23:08:03 +03:00
|
|
|
|
{#key lnurl}
|
2021-09-24 05:28:10 +03:00
|
|
|
|
<a href="lightning:{lnurl}">
|
|
|
|
|
<QR value={lnurl} size="{230}" />
|
|
|
|
|
</a>
|
2021-09-24 23:08:03 +03:00
|
|
|
|
{/key}
|
2021-09-24 05:28:10 +03:00
|
|
|
|
</div>
|
|
|
|
|
<div class="btn-group flex-wrap mt-auto mb-2"
|
|
|
|
|
role="group" class:invisible={!lnurl}>
|
|
|
|
|
<CTC let:id let:action text={lnurl}>
|
|
|
|
|
<button type="button" class="btn btn-outline-secondary"
|
|
|
|
|
id={id} on:click={action}>Copy</button>
|
|
|
|
|
</CTC>
|
|
|
|
|
{#if canShare}
|
|
|
|
|
<button type="button" class="btn btn-outline-secondary"
|
|
|
|
|
on:click={()=>{ navigator.share({text:lnurl})}}>Share
|
|
|
|
|
</button>
|
|
|
|
|
{/if}
|
|
|
|
|
<Tipped let:id>
|
|
|
|
|
<a slot="thing" role="button" class="btn btn-outline-secondary"
|
|
|
|
|
href="lightning:{lnurl}" {id}>Pay</a>
|
|
|
|
|
<div slot="tip">open in your wallet</div>
|
|
|
|
|
</Tipped>
|
|
|
|
|
|
|
|
|
|
<Tipped let:id>
|
|
|
|
|
<button slot="thing" {id} type="button"
|
|
|
|
|
class="btn btn-outline-secondary"
|
|
|
|
|
on:click="{()=>getInvoiceFor=lnurl}">
|
|
|
|
|
Invoice</button>
|
|
|
|
|
<div slot="tip">get an invoice for wallets with no lnurl-pay</div>
|
|
|
|
|
</Tipped>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{#if lightningAddress}
|
2021-09-24 06:18:04 +03:00
|
|
|
|
<CTC let:id let:action force text={lightningAddress}>
|
2021-09-24 05:50:20 +03:00
|
|
|
|
<div class="input-group">
|
2021-09-24 05:28:10 +03:00
|
|
|
|
<div class="input-group-prepend">
|
2021-09-24 05:50:20 +03:00
|
|
|
|
<Tipped let:id>
|
|
|
|
|
<span slot="thing" {id} class="input-group-text">
|
|
|
|
|
<a href="https://lightningaddress.com/">LA:</a>
|
|
|
|
|
</span>
|
|
|
|
|
<div slot="tip">
|
|
|
|
|
Lightning address for this payment
|
|
|
|
|
</div>
|
|
|
|
|
</Tipped>
|
2021-09-24 05:28:10 +03:00
|
|
|
|
</div>
|
2021-09-24 06:18:04 +03:00
|
|
|
|
<input class="user-select-all form-control"
|
2021-09-24 05:28:10 +03:00
|
|
|
|
style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"
|
2021-09-24 06:18:04 +03:00
|
|
|
|
tabindex="0"
|
|
|
|
|
on:click={action} id={id} value={lightningAddress} readonly/>
|
2021-09-24 05:28:10 +03:00
|
|
|
|
</div>
|
|
|
|
|
</CTC>
|
|
|
|
|
{/if}
|
|
|
|
|
|
2021-07-17 13:44:07 +03:00
|
|
|
|
</SiteCard>
|
|
|
|
|
</SiteDeck>
|
|
|
|
|
|
2021-07-18 00:31:56 +03:00
|
|
|
|
<PayFlow bind:lnurl={getInvoiceFor} hasAmount={amounts[payway.id]}/>
|