aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/(app)/send
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes/(app)/send')
-rw-r--r--src/routes/(app)/send/[...text]/+page.svelte12
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/+layout.server.ts23
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/+page.server.ts7
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/+page.svelte10
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts28
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte99
-rw-r--r--src/routes/(app)/send/ecash/+page.svelte19
-rw-r--r--src/routes/(app)/send/invoice/[id]/+page.server.ts13
-rw-r--r--src/routes/(app)/send/invoice/[id]/+page.svelte8
-rw-r--r--src/routes/(app)/send/lightning/[payreq]/+page.server.ts5
-rw-r--r--src/routes/(app)/send/lightning/[payreq]/+page.svelte17
11 files changed, 167 insertions, 74 deletions
diff --git a/src/routes/(app)/send/[...text]/+page.svelte b/src/routes/(app)/send/[...text]/+page.svelte
index 780f70c1..faa4a766 100644
--- a/src/routes/(app)/send/[...text]/+page.svelte
+++ b/src/routes/(app)/send/[...text]/+page.svelte
@@ -5,7 +5,6 @@
import { tick } from "svelte";
import { browser } from "$app/environment";
import { t } from "$lib/translations";
- import AppHeader from "$comp/AppHeader.svelte";
import Avatar from "$comp/Avatar.svelte";
import Icon from "$comp/Icon.svelte";
import Spinner from "$comp/Spinner.svelte";
@@ -19,7 +18,7 @@
let el, text, pasted, w;
- let keypress = (e) => e.key === "Enter" && (e.preventDefault() || el.click());
+ let keypress = (e) => e.key === "Enter" ? (e.preventDefault() || el.click()) : (pasted = false);
let paste = async () => {
text = await navigator.clipboard.readText();
@@ -31,7 +30,6 @@
<svelte:window bind:innerWidth={w} />
-<AppHeader {data} />
<div class="container px-4 max-w-lg mx-auto space-y-5 mt-20">
<h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold">
{$t("payments.send")}
@@ -54,7 +52,7 @@
name="text"
placeholder={$t("user.send.placeholder")}
on:keypress={keypress}
- class="w-full p-4 border rounded-xl h-48 text-xl"
+ class="w-full p-4 border rounded-xl h-32 text-xl"
bind:value={text}
on:paste={() => (pasted = true)}
autocapitalize="none"
@@ -65,7 +63,7 @@
<a href="/scan" class="w-full">
<button
type="button"
- class="flex border rounded-2xl px-6 py-5 font-bold hover:opacity-80 w-full bg-primary justify-center gap-2"
+ class="flex border rounded-2xl px-5 py-4 hover:opacity-80 w-full justify-center gap-2"
>
<Icon icon="camera" style="w-8 my-auto" />
<div class="my-auto">{$t("user.send.scan")}</div>
@@ -74,7 +72,7 @@
<button
type="button"
- class="flex border rounded-2xl px-6 py-5 font-bold hover:opacity-80 w-full bg-primary justify-center gap-2"
+ class="flex border rounded-2xl px-5 py-4 hover:opacity-80 w-full justify-center gap-2"
on:click={paste}
>
<Icon icon="paste" style="w-8 my-auto" />
@@ -97,7 +95,7 @@
type="button"
class="flex border rounded-2xl px-6 py-5 w-full font-bold gap-2 justify-center text-xl bg-primary"
>
- <Icon icon="voucher" style="w-8 my-auto" />
+ <img src="/images/cash.png" class="w-8" />
<div class="my-auto">{$t("payments.createEcash")}</div>
</button>
</a>
diff --git a/src/routes/(app)/send/bitcoin/[address]/+layout.server.ts b/src/routes/(app)/send/bitcoin/[address]/+layout.server.ts
new file mode 100644
index 00000000..a6edf8b0
--- /dev/null
+++ b/src/routes/(app)/send/bitcoin/[address]/+layout.server.ts
@@ -0,0 +1,23 @@
+import { auth, get } from "$lib/utils";
+import { redirect } from "@sveltejs/kit";
+
+export async function load({ cookies, params, parent }) {
+ let { user } = await parent();
+ let aid = cookies.get("aid");
+ let { address } = params;
+ let { balance } = await get(`/account/${aid}`, auth(cookies));
+
+ try {
+ let invoice = await get(`/invoice/${address}`);
+
+ if (invoice) {
+ let recipient = await get(`/users/${invoice.uid}`);
+ if (recipient?.id !== user.id)
+ redirect(307, `/pay/${recipient.username}`);
+ }
+ } catch (e) {
+ // invoice not found
+ }
+
+ return { balance };
+}
diff --git a/src/routes/(app)/send/bitcoin/[address]/+page.server.ts b/src/routes/(app)/send/bitcoin/[address]/+page.server.ts
new file mode 100644
index 00000000..a9b72787
--- /dev/null
+++ b/src/routes/(app)/send/bitcoin/[address]/+page.server.ts
@@ -0,0 +1,7 @@
+import { auth, get } from "$lib/utils";
+
+export async function load({ cookies }) {
+ let aid = cookies.get("aid");
+ let { balance } = await get(`/account/${aid}`, auth(cookies));
+ return { balance };
+}
diff --git a/src/routes/(app)/send/bitcoin/[address]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/+page.svelte
index 838c5c04..6b938c38 100644
--- a/src/routes/(app)/send/bitcoin/[address]/+page.svelte
+++ b/src/routes/(app)/send/bitcoin/[address]/+page.svelte
@@ -8,9 +8,9 @@
export let data;
- let { rates, user } = data;
+ let { balance, rates, user } = data;
let { address } = $page.params;
- let { balance, currency, username } = user;
+ let { currency, username } = user;
let amount = 0;
let submit, fiat;
@@ -24,12 +24,6 @@
};
</script>
-<a href="/send">
- <button type="button" class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80">
- <Icon icon="arrow-left" style="w-10" />
- </button>
-</a>
-
<div class="container px-4 max-w-xl mx-auto space-y-5 text-center">
<h1 class="text-3xl md:text-4xl font-semibold mb-2">{$t("payments.send")}</h1>
diff --git a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts
index 7efe6e49..e46a9f56 100644
--- a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts
+++ b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.server.ts
@@ -1,15 +1,29 @@
import { fail, redirect } from "@sveltejs/kit";
-import { auth, post, fd } from "$lib/utils";
+import { auth, get, post, fd } from "$lib/utils";
export async function load({ params: { address, amount, feeRate }, cookies }) {
+ let aid = cookies.get("aid");
+
try {
- let { fee, fees, ourfee, hex } = await post(
+ let { fee, fees, inputs, ourfee, hex } = await post(
"/bitcoin/fee",
- { address, amount, feeRate },
+ { address, amount, feeRate, aid },
auth(cookies)
);
- return { amount, address, fee, fees, feeRate, ourfee, hex };
+ let account = await get(`/account/${aid}`, auth(cookies));
+
+ return {
+ account,
+ amount,
+ address,
+ fee,
+ fees,
+ feeRate,
+ ourfee,
+ hex,
+ inputs,
+ };
} catch (e: any) {
return { amount, address, feeRate, message: e.message };
}
@@ -21,13 +35,15 @@ export const actions = {
params: { address, amount, feeRate },
request,
}) => {
+ let p;
try {
- await post("/bitcoin/send", await fd(request), auth(cookies));
+ let body = await fd(request);
+ p = await post("/bitcoin/send", body, auth(cookies));
} catch (e: any) {
console.log("problem sending bitcoin", e);
return fail(400, { address, amount, feeRate, message: e.message });
}
- redirect(307, "/sent");
+ redirect(307, `/sent/${p.id}`);
},
};
diff --git a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
index 84506e6b..ba87436f 100644
--- a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
+++ b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
@@ -1,20 +1,96 @@
<script>
+ import { tick } from "svelte";
import { t } from "$lib/translations";
import { enhance } from "$app/forms";
import Toggle from "$comp/Toggle.svelte";
import Icon from "$comp/Icon.svelte";
import Spinner from "$comp/Spinner.svelte";
+ import WalletPass from "$comp/WalletPass.svelte";
import { page } from "$app/stores";
- import { fiat as toFiat, f, focus, s, sat, closest } from "$lib/utils";
+ import {
+ fiat as toFiat,
+ f,
+ focus,
+ s,
+ sat,
+ closest,
+ network,
+ } from "$lib/utils";
import { pin } from "$lib/store";
import { goto, invalidate } from "$app/navigation";
import { rate } from "$lib/store";
+ import { applyAction } from "$app/forms";
+ import { hex as hexUtil } from "@scure/base";
+ import * as btc from "@scure/btc-signer";
+ import { hash160 } from "@scure/btc-signer/utils";
+ import { decrypt } from "nostr-tools/nip49";
+ import { HDKey } from "@scure/bip32";
+ import { entropyToMnemonic, mnemonicToSeed } from "@scure/bip39";
+ import { wordlist } from "@scure/bip39/wordlists/english";
export let data;
export let form;
- let { amount, address, message, fee, fees, feeRate, ourfee, rates, hex } =
- data;
+ let { encode, decode } = hexUtil;
+ let passwordPrompt;
+ let password;
+ let cancel = () => (passwordPrompt = false);
+ let signed;
+
+ let togglePassword = () => (passwordPrompt = !passwordPrompt);
+ let handler = ({ cancel }) => {
+ if (account.seed && !signed) cancel(), togglePassword();
+ return async ({ result }) => {
+ if (result.type === "redirect") {
+ goto(result.location);
+ } else {
+ await applyAction(result);
+ invalidate("app:payments");
+ }
+ };
+ };
+
+ let signTx = async () => {
+ let entropy = await decrypt(account.seed, password);
+ let mnemonic = entropyToMnemonic(entropy, wordlist);
+ let seed = await mnemonicToSeed(mnemonic, password);
+ let master = HDKey.fromMasterSeed(seed, network);
+ let child = master.derive("m/84'/0'/0'");
+
+ let tx = btc.Transaction.fromRaw(decode(hex));
+
+ for (let [i, input] of tx.inputs.entries()) {
+ let { witnessUtxo, path } = inputs[i];
+ witnessUtxo.amount = BigInt(witnessUtxo.amount);
+ witnessUtxo.script = decode(witnessUtxo.script);
+ let key = child.derive(path);
+ tx.updateInput(i, { witnessUtxo });
+ tx.signIdx(key.privateKey, i);
+ }
+
+ tx.finalize();
+ hex = tx.hex;
+ console.log("HEX", hex);
+ signed = true;
+ await tick();
+ submit.click();
+ };
+
+ let toggle = () => (submitting = !submitting);
+
+ let {
+ account,
+ amount,
+ address,
+ message,
+ fee,
+ fees,
+ feeRate,
+ ourfee,
+ rates,
+ hex,
+ inputs,
+ } = data;
$: reload(data);
let reload = () => {
@@ -48,15 +124,6 @@
let goBack = () => goto(`/send/bitcoin/${address}`);
</script>
-<button
- type="button"
- class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80"
- data-sveltekit-preload-data="false"
- on:click={goBack}
->
- <Icon icon="arrow-left" style="w-10" />
-</button>
-
<div
class="container px-4 max-w-xl mx-auto space-y-5 text-center no-transition"
>
@@ -115,10 +182,12 @@
</div>
{/if}
- <form method="POST" use:enhance on:submit={() => (submitting = true)}>
+ <form method="POST" use:enhance={handler}>
<input name="pin" value={$pin} type="hidden" />
<input name="hex" value={hex} type="hidden" />
<input name="rate" value={$rate} type="hidden" />
+ <input name="aid" value={account.id} type="hidden" />
+ <input name="signed" value={signed} type="hidden" />
<div class="flex justify-center gap-2">
<button
@@ -139,6 +208,10 @@
{/if}
</div>
+{#if passwordPrompt}
+ <WalletPass bind:password bind:cancel submit={signTx} />
+{/if}
+
<style>
.no-transition {
view-transition-name: fee;
diff --git a/src/routes/(app)/send/ecash/+page.svelte b/src/routes/(app)/send/ecash/+page.svelte
index 15c7c5d3..ef8e368c 100644
--- a/src/routes/(app)/send/ecash/+page.svelte
+++ b/src/routes/(app)/send/ecash/+page.svelte
@@ -29,25 +29,15 @@
let toggle = () => (submitting = !submitting);
</script>
-<a href="/send">
- <button type="button" class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80">
- <Icon icon="arrow-left" style="w-10" />
- </button>
-</a>
-
<div class="container px-4 max-w-xl mx-auto space-y-5 text-center">
- <h1 class="text-3xl md:text-4xl font-semibold mb-2">
- {$t("payments.createEcash")}
- </h1>
-
<form use:enhance={handler(toggle)} method="POST">
<Numpad bind:amount bind:fiat {currency} {submit} bind:rate={$rate} />
<input type="hidden" name="amount" bind:value={amount} />
- <div class="flex justify-center gap-2">
+ <div>
<button
type="button"
- class="hover:opacity-80 bg-black text-white rounded-2xl py-3 px-4 mt-2 border font-bold"
+ class="hover:opacity-80 rounded-2xl py-3 px-4 mt-2 border font-bold w-full max-w-[340px] mx-auto"
on:click|preventDefault={setMax}
disabled={submitting}
on:keydown={setMax}>Max ⚡️{s(balance)}</button
@@ -57,12 +47,13 @@
use:focus
bind:this={submit}
type="submit"
- class="opacity-100 hover:opacity-80 rounded-2xl border py-3 font-bold mt-2 bg-black text-white px-4 w-24"
+ class="opacity-100 hover:opacity-80 rounded-2xl border py-3 font-bold mt-2 bg-black text-white px-4 w-full flex justify-center gap-2 max-w-[340px] mx-auto"
>
{#if submitting}
<Spinner />
{:else}
- {$t("payments.mint")}
+ <img src="/images/cash.png" class="w-8" />
+ <div class="my-auto">{$t("payments.mint")}</div>
{/if}
</button>
</div>
diff --git a/src/routes/(app)/send/invoice/[id]/+page.server.ts b/src/routes/(app)/send/invoice/[id]/+page.server.ts
index ed0198cf..6c89912d 100644
--- a/src/routes/(app)/send/invoice/[id]/+page.server.ts
+++ b/src/routes/(app)/send/invoice/[id]/+page.server.ts
@@ -7,31 +7,32 @@ export async function load({ params: { id }, parent }) {
let invoice = await get(`/invoice/${id}`);
if (invoice.prompt && invoice.tip === null)
- redirect(307, `/${invoice.user.username}/invoice/${id}/tip`);
+ redirect(307, `/invoice/${id}/tip`);
if (invoice.memoPrompt && invoice.memo === null)
- redirect(307, `/${invoice.user.username}/invoice/${id}/memo`);
+ redirect(307, `/invoice/${id}/memo`);
- if (invoice.user.username === user?.username)
+ if (invoice.account === user?.id)
error(500, { message: "Cannot send to self" });
- if (!user) redirect(307, `/${invoice.user.username}/invoice/${id}`);
+ if (!user) redirect(307, `/invoice/${id}`);
return { invoice, rates, user };
}
export const actions = {
default: async ({ cookies, params: { id }, request }) => {
+ let p;
try {
let body = await fd(request);
body.hash = id;
- await post("/payments", body, auth(cookies));
+ p = await post("/payments", body, auth(cookies));
} catch (e: any) {
console.log("payment failed", id, e);
error(500, e.message);
}
- redirect(307, "/sent");
+ redirect(307, `/sent/${p.id}`);
},
};
diff --git a/src/routes/(app)/send/invoice/[id]/+page.svelte b/src/routes/(app)/send/invoice/[id]/+page.svelte
index 81a2c521..4348e473 100644
--- a/src/routes/(app)/send/invoice/[id]/+page.svelte
+++ b/src/routes/(app)/send/invoice/[id]/+page.svelte
@@ -52,7 +52,7 @@
let toggle = () => (submitting = !submitting);
let external = async () => {
- let { id } = await post(`/${recipient.username}/invoice`, {
+ let { id } = await post(`/invoice`, {
invoice: {
...invoice,
type: "lightning",
@@ -62,7 +62,7 @@
user: { username: recipient.username },
});
- goto(`/${recipient.username}/invoice/${id}?options=true`, {
+ goto(`/invoice/${id}?options=true`, {
invalidateAll: true,
});
};
@@ -93,10 +93,6 @@
// });
</script>
-<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={back}>
- <Icon icon="arrow-left" style="w-10" />
-</button>
-
{#if form?.message}
<div class="text-red-600 text-center">
{form.message}
diff --git a/src/routes/(app)/send/lightning/[payreq]/+page.server.ts b/src/routes/(app)/send/lightning/[payreq]/+page.server.ts
index ddec2968..3e87fa53 100644
--- a/src/routes/(app)/send/lightning/[payreq]/+page.server.ts
+++ b/src/routes/(app)/send/lightning/[payreq]/+page.server.ts
@@ -9,16 +9,17 @@ export const actions = {
setAmount: async ({ request }) => fd(request),
send: async ({ cookies, request }) => {
+ let p;
try {
let body = await fd(request);
- await post("/payments", body, auth(cookies));
+ p = await post("/payments", body, auth(cookies));
} catch (e: any) {
if (e.message.includes("unusable"))
e.message = "Failed to route payment, try sending a lower amount";
return fail(400, { message: e.message });
}
- redirect(307, "/sent");
+ redirect(307, `/sent/${p.id}`);
},
};
diff --git a/src/routes/(app)/send/lightning/[payreq]/+page.svelte b/src/routes/(app)/send/lightning/[payreq]/+page.svelte
index 57a17e01..74c100f8 100644
--- a/src/routes/(app)/send/lightning/[payreq]/+page.svelte
+++ b/src/routes/(app)/send/lightning/[payreq]/+page.svelte
@@ -58,11 +58,7 @@
let toggle = () => (show = !show);
</script>
-<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={back}>
- <Icon icon="arrow-left" style="w-10" />
-</button>
-
-<div class="container px-4 max-w-xl mx-auto text-center space-y-5">
+<div class="container px-4 max-w-xl mx-auto text-center space-y-2">
{#if amount}
{#if form?.message}
<div class="text-red-600 text-center">
@@ -81,12 +77,9 @@
<h3 class="text-secondary text-xl">⚡️{s(amount)}</h3>
</div>
- <div>
- <div class="text-lg text-secondary">
- {$t("payments.to")}
- </div>
-
- <p class="text-2xl break-words font-semibold mb-8">{alias}</p>
+ <div class="text-xl">
+ <span class="text-secondary">{$t("payments.to")}</span>
+ <span class="break-words font-semibold">{alias}</span>
</div>
{#if ourfee}
@@ -109,7 +102,7 @@
use:enhance
on:submit={submit}
action="?/send"
- class="space-y-5"
+ class="space-y-2"
>
<input name="payreq" value={payreq} type="hidden" />
<input name="amount" value={amount} type="hidden" />