aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2025-11-26 21:44:55 -0800
committerAdam Soltys <[email protected]>2026-02-11 15:33:08 -0800
commit3aab57df2063d913bd16b953187ced242421f66a (patch)
tree9f8fcb8d266e00e1112af106d1480e9fc08e8b04 /src
parent68e7fe9655f94efc573f3aab7acf60d03c4162a0 (diff)
downloadcoinos-ui-3aab57df2063d913bd16b953187ced242421f66a.tar.gz
coinos-ui-3aab57df2063d913bd16b953187ced242421f66a.zip
ark stuff
Diffstat (limited to 'src')
-rw-r--r--src/components/Account.svelte86
-rw-r--r--src/components/InvoiceActions.svelte32
-rw-r--r--src/lib/ark.ts97
-rw-r--r--src/lib/parse.ts4
-rw-r--r--src/routes/(app)/+layout.svelte14
-rw-r--r--src/routes/(app)/account/ark/+page.svelte228
-rw-r--r--src/routes/(app)/account/bitcoin/+page.svelte34
-rw-r--r--src/routes/(app)/account/savings/+page.svelte49
-rw-r--r--src/routes/(app)/ark/+page.server.ts11
-rw-r--r--src/routes/(app)/ark/+page.svelte113
-rw-r--r--src/routes/(app)/invoice/[id]/+layout.server.ts1
-rw-r--r--src/routes/(app)/send/ark/[address]/+page.svelte3
12 files changed, 395 insertions, 277 deletions
diff --git a/src/components/Account.svelte b/src/components/Account.svelte
index 744821a3..d37101ee 100644
--- a/src/components/Account.svelte
+++ b/src/components/Account.svelte
@@ -1,20 +1,61 @@
<script>
+ import { hex } from "@scure/base";
+ import WalletPass from "$comp/WalletPass.svelte";
import { run } from "svelte/legacy";
-
+ import { onMount } from "svelte";
import { goto } from "$app/navigation";
import Icon from "$comp/Icon.svelte";
import Balance from "$comp/Balance.svelte";
import { t } from "$lib/translations";
+ import { decrypt } from "nostr-tools/nip49";
+ import { arkkey } from "$lib/ark";
let { user, rate, account, last } = $props();
- let { name, seed, balance, id } = $derived(account);
+ let {
+ name,
+ seed,
+ balance,
+ id,
+ type: accountType,
+ arkAddress,
+ } = $derived(account);
+
+ let arkBalance = $state(0);
+ let arkLoading = $state(false);
+ let passwordPrompt = $state(false);
+ let password = $state();
+ let pendingUrl = $state();
+ let cancel = $state(() => {
+ passwordPrompt = false;
+ pendingUrl = undefined;
+ });
+
+ let setAccount = (event, url) => {
+ event.preventDefault();
+ document.cookie = `aid=${id}; path=/; max-age=86400`;
+ if (isArk) {
+ pendingUrl = url;
+ if ($arkkey) goto(pendingUrl);
+ else passwordPrompt = true;
+ } else {
+ $arkkey = undefined;
+ goto(url);
+ }
+ };
- let setAccount = () => (document.cookie = `aid=${id}; path=/; max-age=86400`);
- let go = () => {
- setAccount();
- goto("/payments");
+ let submitPassword = () => {
+ $arkkey = hex.encode(decrypt(seed, password));
+ passwordPrompt = false;
+ if (pendingUrl) {
+ goto(pendingUrl);
+ pendingUrl = undefined;
+ }
};
- let type = $derived(seed ? "Savings" : "Cash");
+
+ let displayType = $derived(
+ accountType === "ark" ? "Ark" : seed ? "Savings" : "Cash",
+ );
+ let isArk = $derived(accountType === "ark");
</script>
<div
@@ -43,7 +84,11 @@
</div>
<div class="flex justify-center w-full text-xl gap-2">
- <a href={"/invoice"} class="contents" onclick={setAccount}>
+ <a
+ href={"/invoice"}
+ class="contents"
+ onclick={(e) => setAccount(e, "/invoice")}
+ >
<button class="btn !w-auto flex-grow">
<iconify-icon
noobserver
@@ -55,7 +100,26 @@
</button>
</a>
- <a href={`/send`} class="contents grow" onclick={setAccount}>
+ <a
+ href={"/payments"}
+ class="contents"
+ onclick={(e) => setAccount(e, "/payments")}
+ >
+ <button class="btn !w-auto flex-grow">
+ <iconify-icon
+ noobserver
+ icon="ph:clock-bold"
+ width="32"
+ flip="horizontal"
+ ></iconify-icon>
+ </button>
+ </a>
+
+ <a
+ href={`/send`}
+ class="contents grow"
+ onclick={(e) => setAccount(e, "/send")}
+ >
<button type="button" class="btn !w-auto flex-grow">
<iconify-icon noobserver icon="ph:paper-plane-right-bold" width="32"
></iconify-icon>
@@ -64,3 +128,7 @@
</a>
</div>
</div>
+
+{#if passwordPrompt}
+ <WalletPass bind:password bind:cancel submit={submitPassword} />
+{/if}
diff --git a/src/components/InvoiceActions.svelte b/src/components/InvoiceActions.svelte
index 08f9920d..b6005217 100644
--- a/src/components/InvoiceActions.svelte
+++ b/src/components/InvoiceActions.svelte
@@ -19,7 +19,7 @@
toggleMemo,
} = $props();
- let { aid, address_type, type } = $derived(invoice);
+ let { aid, account, address_type, type } = $derived(invoice);
</script>
<div class="text-secondary space-y-2 text-xl pt-2">
@@ -133,7 +133,9 @@
</div>
<div class="my-auto text-lg">Lightning</div>
</button>
- {:else}
+ {/if}
+
+ {#if account?.type === types.ark}
<button
class="btn flex-nowrap !w-auto grow"
class:bg-base-300={type === types.ark}
@@ -148,22 +150,26 @@
class="bg-black rounded-full w-8 h-8 items-center justify-center flex"
>
<div class="m-auto">
- <img src="/images/ark.png" class="w-8 h-8 rounded-full object-cover" alt="Bitcoin" />
+ <img
+ src="/images/ark.png"
+ class="w-8 h-8 rounded-full object-cover"
+ alt="Bitcoin"
+ />
</div>
</div>
<div class="my-auto text-lg">Ark</div>
</button>
+ {:else}
+ <button
+ class="btn flex-nowrap !w-auto grow"
+ class:bg-base-300={type === types.bitcoin}
+ class:text-secondary={type === types.bitcoin}
+ onclick={() => setType(types.bitcoin)}
+ >
+ <img src="/images/bitcoin.svg" class="w-8" alt="Bitcoin" />
+ <div class="my-auto text-lg">Bitcoin</div>
+ </button>
{/if}
-
- <button
- class="btn flex-nowrap !w-auto grow"
- class:bg-base-300={type === types.bitcoin}
- class:text-secondary={type === types.bitcoin}
- onclick={() => setType(types.bitcoin)}
- >
- <img src="/images/bitcoin.svg" class="w-8" alt="Bitcoin" />
- <div class="my-auto text-lg">Bitcoin</div>
- </button>
</div>
{#if aid === user.id}
diff --git a/src/lib/ark.ts b/src/lib/ark.ts
index 7649a6bf..487898ae 100644
--- a/src/lib/ark.ts
+++ b/src/lib/ark.ts
@@ -1,54 +1,13 @@
import { persistLocal } from "$lib/store";
-import { get } from "svelte/store";
import { SingleKey, Wallet } from "@arkade-os/sdk";
-import { bytesToHex, randomBytes } from "@noble/hashes/utils";
-import { nip19 } from "nostr-tools";
-import { hex } from "@scure/base";
+import { get } from "svelte/store";
export const arkServerUrl = "http://localhost:7070";
export const arkkey = persistLocal("arkkey", "");
-export const generateKey = (): string => {
- const privateKey = bytesToHex(randomBytes(32));
- arkkey.set(privateKey);
- return privateKey;
-};
-
-export const getKey = (): string => {
- let key = get(arkkey);
- if (!key) {
- key = generateKey();
- }
- return key;
-};
-
-export const hasKey = (): boolean => {
- return !!get(arkkey);
-};
-
-export const clearKey = (): void => {
- arkkey.set("");
-};
-
-export const keyToNsec = (key?: string): string => {
- const k = key || getKey();
- return nip19.nsecEncode(hex.decode(k));
-};
-
-export const nsecToKey = (nsec: string): string => {
- const { type, data } = nip19.decode(nsec);
- if (type !== "nsec") throw new Error("Invalid nsec format");
- return bytesToHex(data);
-};
-
-export const restoreFromNsec = (nsec: string): string => {
- const key = nsecToKey(nsec);
- arkkey.set(key);
- return key;
-};
-
export const getWallet = async () => {
- const key = getKey();
+ const key = get(arkkey);
+ if (!key) return;
const identity = SingleKey.fromHex(key);
return Wallet.create({
@@ -62,55 +21,7 @@ export const getAddress = async (): Promise<string> => {
return wallet.getAddress();
};
-export const getBalance = async (): Promise<{ available: number; pending: number }> => {
+export const getBalance = async (): Promise<{ available: number }> => {
const wallet = await getWallet();
return wallet.getBalance();
};
-
-export const syncArkAddress = async (
- currentAddress: string | undefined,
- updateFn: (arkAddress: string) => Promise<void>
-): Promise<string> => {
- const address = await getAddress();
- if (address !== currentAddress) {
- await updateFn(address);
- }
- return address;
-};
-
-export const sendArk = async (address: string, amount: number): Promise<string> => {
- const wallet = await getWallet();
- const vtxos = await wallet.getVtxos();
-
- // Sort by expiry (spend oldest first)
- const sorted = vtxos.sort(
- (a, b) => (a.virtualStatus.batchExpiry ?? 0) - (b.virtualStatus.batchExpiry ?? 0)
- );
-
- // Select inputs
- const inputs = [];
- let selectedAmount = 0;
- for (const vtxo of sorted) {
- if (selectedAmount >= amount) break;
- inputs.push(vtxo);
- selectedAmount += vtxo.value;
- }
-
- if (selectedAmount < amount) {
- throw new Error(`Insufficient funds: have ${selectedAmount}, need ${amount}`);
- }
-
- // Build outputs
- const outputs: { address: string; amount: bigint }[] = [
- { address, amount: BigInt(amount) }
- ];
-
- // Add change output if needed
- const change = selectedAmount - amount;
- if (change > 0) {
- const changeAddress = await wallet.getAddress();
- outputs.push({ address: changeAddress, amount: BigInt(change) });
- }
-
- return wallet.settle({ inputs, outputs });
-};
diff --git a/src/lib/parse.ts b/src/lib/parse.ts
index c69032d1..bbcab429 100644
--- a/src/lib/parse.ts
+++ b/src/lib/parse.ts
@@ -11,7 +11,9 @@ export default async (s, host, cookies) => {
let invoice;
let user;
- if (t.startsWith("ark")) redirect(307, `/send/ark/${t}`);
+ if (t.startsWith("ark") || t.startsWith("tark"))
+ redirect(307, `/send/ark/${t}`);
+
if (t.startsWith("http")) redirect(307, t);
if (t.startsWith(host)) redirect(307, `http://${t}`);
diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte
index ed76e103..6624fff8 100644
--- a/src/routes/(app)/+layout.svelte
+++ b/src/routes/(app)/+layout.svelte
@@ -76,19 +76,7 @@
if (user) {
const wallet = await getWallet();
- wallet.notifyIncomingFunds(handleArkPayment);
-
- // Sync ARK address with backend if changed
- const arkAddress = await getAddress();
- if (arkAddress !== user.arkAddress) {
- try {
- console.log("SYNCING", arkAddress);
- await post("/post/user", { arkAddress });
- user.arkAddress = arkAddress;
- } catch (e) {
- console.error("Failed to sync ARK address:", e);
- }
- }
+ if (wallet) wallet.notifyIncomingFunds(handleArkPayment);
}
// if (window.NDEFReader) {
diff --git a/src/routes/(app)/account/ark/+page.svelte b/src/routes/(app)/account/ark/+page.svelte
new file mode 100644
index 00000000..ff313664
--- /dev/null
+++ b/src/routes/(app)/account/ark/+page.svelte
@@ -0,0 +1,228 @@
+<script lang="ts">
+ import { preventDefault } from "svelte/legacy";
+ import { tick, onMount } from "svelte";
+ import { t } from "$lib/translations";
+ import Spinner from "$comp/Spinner.svelte";
+ import { encrypt } from "nostr-tools/nip49";
+ import { bytesToHex, randomBytes } from "@noble/hashes/utils";
+ import { nip19 } from "nostr-tools";
+ import { hex } from "@scure/base";
+ import { focus, fail, post, copy } from "$lib/utils";
+ import { goto } from "$app/navigation";
+ import { SingleKey, Wallet } from "@arkade-os/sdk";
+ import { arkServerUrl } from "$lib/ark";
+
+ let { data } = $props();
+ let { user } = data;
+
+ let privateKey = $state("");
+ let arkAddress = $state("");
+ let nsec = $state("");
+ let showNsec = $state(false);
+ let confirmed = $state(false);
+ let submitting = $state(false);
+
+ let password = $state("");
+ let confirm = $state("");
+ let revealPassword = $state(false);
+ let revealConfirm = $state(false);
+
+ let name = "Ark Vault";
+ let type = "ark";
+
+ onMount(() => {
+ generateKey();
+ });
+
+ let generateKey = async () => {
+ privateKey = bytesToHex(randomBytes(32));
+ nsec = nip19.nsecEncode(hex.decode(privateKey));
+ showNsec = false;
+ confirmed = false;
+
+ // Derive the ARK address from the private key
+ const identity = SingleKey.fromHex(privateKey);
+ const wallet = await Wallet.create({ identity, arkServerUrl });
+ arkAddress = await wallet.getAddress();
+ };
+
+ let revealNsec = () => {
+ showNsec = true;
+ };
+
+ let confirmBackup = () => {
+ confirmed = true;
+ };
+
+ let submit = async () => {
+ if (!confirmed) {
+ fail("Please backup your key first");
+ return;
+ }
+
+ if (!password || password !== confirm) {
+ fail($t("accounts.passwordMismatch"));
+ return;
+ }
+
+ submitting = true;
+ await tick();
+
+ try {
+ // Encrypt the private key using NIP-49
+ let seed = await encrypt(hex.decode(privateKey), password);
+
+ await post("/account", { name, seed, type, arkAddress });
+ goto(`/${user.username}`);
+ } catch (e) {
+ console.log(e);
+ fail(e.message);
+ }
+
+ submitting = false;
+ };
+</script>
+
+<div class="space-y-5">
+ <div class="flex items-center justify-center gap-2">
+ <iconify-icon noobserver icon="ph:vault-bold" width="32"></iconify-icon>
+ <h1 class="text-3xl font-semibold">Create Ark Wallet</h1>
+ </div>
+
+ <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5">
+ {#if !confirmed}
+ <div class="space-y-4">
+ <p class="text-secondary">
+ Your Ark wallet is secured by a private key. Back it up now - you won't be able to see it again without your password.
+ </p>
+
+ {#if showNsec}
+ <div class="space-y-2">
+ <div class="text-sm text-secondary">Your backup key (nsec)</div>
+ <div
+ class="text-sm break-all bg-warning/20 p-4 rounded-lg cursor-pointer border border-warning font-mono"
+ onclick={() => copy(nsec)}
+ >
+ {nsec}
+ </div>
+ <div class="text-sm text-warning">
+ Click to copy. Store this somewhere safe - anyone with this key can spend your funds.
+ </div>
+ </div>
+
+ <div class="flex gap-2">
+ <button type="button" class="btn flex-grow" onclick={generateKey}>
+ <iconify-icon noobserver icon="ph:dice-three-bold" width="24"></iconify-icon>
+ Regenerate
+ </button>
+ <button type="button" class="btn btn-accent flex-grow" onclick={confirmBackup}>
+ <iconify-icon noobserver icon="ph:check-bold" width="24"></iconify-icon>
+ I've backed it up
+ </button>
+ </div>
+ {:else}
+ <button type="button" class="btn btn-warning w-full" onclick={revealNsec}>
+ <iconify-icon noobserver icon="ph:eye-bold" width="24"></iconify-icon>
+ Reveal backup key
+ </button>
+ {/if}
+ </div>
+ {:else}
+ <form onsubmit={preventDefault(submit)} class="space-y-5">
+ <p class="text-secondary">
+ Set a password to encrypt your key. You'll need this password to send funds.
+ </p>
+
+ <label
+ for="password"
+ class="input flex items-center justify-center gap-2 w-full"
+ >
+ {#if revealPassword}
+ <input
+ name="password"
+ type="text"
+ required
+ bind:value={password}
+ autocapitalize="none"
+ class="clean"
+ placeholder="Password"
+ />
+ {:else}
+ <input
+ use:focus
+ name="password"
+ type="password"
+ placeholder="Password"
+ required
+ bind:value={password}
+ autocapitalize="none"
+ class="clean"
+ />
+ {/if}
+
+ <iconify-icon
+ noobserver
+ class="cursor-pointer ml-auto"
+ onclick={() => (revealPassword = !revealPassword)}
+ icon={revealPassword ? "ph:eye-bold" : "ph:eye-slash-bold"}
+ width="32"
+ ></iconify-icon>
+ </label>
+
+ <label
+ for="confirm"
+ class="input flex items-center justify-center gap-2 w-full"
+ >
+ {#if revealConfirm}
+ <input
+ name="confirm"
+ type="text"
+ placeholder="Confirm password"
+ required
+ bind:value={confirm}
+ autocapitalize="none"
+ class="clean"
+ />
+ {:else}
+ <input
+ type="password"
+ placeholder="Confirm password"
+ required
+ bind:value={confirm}
+ autocapitalize="none"
+ class="clean"
+ />
+ {/if}
+ <iconify-icon
+ noobserver
+ class="cursor-pointer ml-auto"
+ onclick={() => (revealConfirm = !revealConfirm)}
+ icon={revealConfirm ? "ph:eye-bold" : "ph:eye-slash-bold"}
+ width="32"
+ ></iconify-icon>
+ </label>
+
+ <div class="flex gap-2">
+ <button
+ type="button"
+ class="btn !w-auto grow"
+ onclick={() => (confirmed = false)}
+ >
+ Back
+ </button>
+ <button
+ disabled={submitting}
+ type="submit"
+ class="btn btn-accent !w-auto grow"
+ >
+ {#if submitting}
+ <Spinner />
+ {:else}
+ Create Wallet
+ {/if}
+ </button>
+ </div>
+ </form>
+ {/if}
+ </div>
+</div>
diff --git a/src/routes/(app)/account/bitcoin/+page.svelte b/src/routes/(app)/account/bitcoin/+page.svelte
new file mode 100644
index 00000000..d45ff8c6
--- /dev/null
+++ b/src/routes/(app)/account/bitcoin/+page.svelte
@@ -0,0 +1,34 @@
+<script>
+ import { t } from "$lib/translations";
+</script>
+
+<div class="space-y-5">
+ <h1 class="text-center text-3xl font-semibold">
+ {$t("accounts.accountSetup")}
+ </h1>
+
+ <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5">
+ <a href="/account/seed" class="block">
+ <div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200">
+ <figure class="w-20 flex items-center justify-center">
+ <iconify-icon noobserver icon="ph:file-plus-bold" width="64"></iconify-icon>
+ </figure>
+ <div>
+ <div class="text-xl">{$t("accounts.create")}</div>
+ <div class="text-secondary">{$t("accounts.generateSeed")}</div>
+ </div>
+ </div>
+ </a>
+ <a href="/account/import" class="block">
+ <div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200">
+ <figure class="w-20 flex items-center justify-center">
+ <iconify-icon noobserver icon="ph:folder-open-bold" width="64"></iconify-icon>
+ </figure>
+ <div>
+ <div class="text-xl">{$t("accounts.import")}</div>
+ <div class="text-secondary">{$t("accounts.importSeed")}</div>
+ </div>
+ </div>
+ </a>
+ </div>
+</div>
diff --git a/src/routes/(app)/account/savings/+page.svelte b/src/routes/(app)/account/savings/+page.svelte
index 22d550b4..a474ad52 100644
--- a/src/routes/(app)/account/savings/+page.svelte
+++ b/src/routes/(app)/account/savings/+page.svelte
@@ -1,37 +1,40 @@
<script>
import { t } from "$lib/translations";
- import Icon from "$comp/Icon.svelte";
</script>
<div class="space-y-5">
<h1 class="text-center text-3xl font-semibold">
- {$t("accounts.accountSetup")}
+ Choose wallet type
</h1>
- <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-2">
- <div class="space-y-5">
- <a href="/account/seed" class="block">
- <div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200">
- <figure class="w-20">
- <iconify-icon noobserver icon="ph:file-plus-bold" width="64"></iconify-icon>
- </figure>
- <div>
- <div class="text-xl">{$t("accounts.create")}</div>
- <div class="text-secondary">{$t("accounts.generateSeed")}</div>
+ <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5">
+ <a href="/account/bitcoin" class="block">
+ <div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200">
+ <figure class="w-20 flex items-center justify-center">
+ <iconify-icon noobserver icon="ph:coins-bold" width="64"></iconify-icon>
+ </figure>
+ <div>
+ <div class="text-xl">Bitcoin (On-chain)</div>
+ <div class="text-secondary">
+ Standard Bitcoin wallet secured by a 12-word seed phrase.
+ Full control over your UTXOs.
</div>
</div>
- </a>
- <a href="/account/import" class="block">
- <div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200">
- <figure class="w-20">
- <iconify-icon noobserver icon="ph:folder-open-bold" width="64"></iconify-icon>
- </figure>
- <div>
- <div class="text-xl">{$t("accounts.import")}</div>
- <div class="text-secondary">{$t("accounts.importSeed")}</div>
+ </div>
+ </a>
+ <a href="/account/ark" class="block">
+ <div class="card card-side shadow shadow-base-300 p-8 hover:bg-base-200">
+ <figure class="w-20 flex items-center justify-center">
+ <iconify-icon noobserver icon="ph:vault-bold" width="64"></iconify-icon>
+ </figure>
+ <div>
+ <div class="text-xl">Ark (Off-chain)</div>
+ <div class="text-secondary">
+ Fast, private transactions using virtual UTXOs.
+ Lower fees with instant settlement.
</div>
</div>
- </a>
- </div>
+ </div>
+ </a>
</div>
</div>
diff --git a/src/routes/(app)/ark/+page.server.ts b/src/routes/(app)/ark/+page.server.ts
deleted file mode 100644
index bac0a02a..00000000
--- a/src/routes/(app)/ark/+page.server.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import getRates from "$lib/rates";
-
-export async function load({ depends, parent }) {
- depends("app:payments");
- depends("app:items");
-
- const { user } = await parent();
-
- const rates = await getRates();
- return { rate: rates[user.currency] };
-}
diff --git a/src/routes/(app)/ark/+page.svelte b/src/routes/(app)/ark/+page.svelte
deleted file mode 100644
index 3089d887..00000000
--- a/src/routes/(app)/ark/+page.svelte
+++ /dev/null
@@ -1,113 +0,0 @@
-<script>
- import { onMount } from "svelte";
- import { getBalance, getAddress, keyToNsec } from "$lib/ark";
- import Amount from "$comp/Amount.svelte";
- import { s, copy } from "$lib/utils";
- import { t } from "$lib/translations";
-
- let { data } = $props();
- let { user, rate } = $derived(data);
-
- let loading = $state(true);
- let balance = $state({ available: 0, pending: 0 });
- let address = $state("");
- let showNsec = $state(false);
- let nsec = $state("");
-
- onMount(async () => {
- await refresh();
- });
-
- let refresh = async () => {
- loading = true;
- try {
- [balance, address] = await Promise.all([getBalance(), getAddress()]);
- } catch (e) {
- console.error("Failed to load ARK wallet:", e);
- }
- loading = false;
- };
-
- let revealNsec = () => {
- nsec = keyToNsec();
- showNsec = true;
- };
-
- let copyNsec = () => {
- copy(nsec);
- };
-</script>
-
-<div class="space-y-5">
- <div class="flex items-center justify-center gap-2">
- <iconify-icon noobserver icon="ph:vault-bold" width="32"></iconify-icon>
- <h1 class="text-3xl font-semibold">Ark Wallet</h1>
- </div>
-
- <div class="container w-full mx-auto px-4 max-w-xl space-y-5">
- {#if loading}
- <div class="flex justify-center py-8">
- <div class="loading loading-spinner loading-lg"></div>
- </div>
- {:else}
- <div class="text-center space-y-2">
- <Amount
- amount={balance.available}
- {rate}
- currency={user?.currency || "USD"}
- />
- {#if balance.pending > 0}
- <div class="text-sm text-warning">
- +{s(balance.pending)} pending
- </div>
- {/if}
- </div>
-
- <div class="flex gap-2 justify-center w-full text-xl">
- <a href="/invoice" class="btn flex-grow">
- <iconify-icon noobserver icon="ph:hand-coins-bold" width="24" flip="horizontal"></iconify-icon>
- Receive
- </a>
- <a href="/send" class="btn flex-grow">
- <iconify-icon noobserver icon="ph:paper-plane-right-bold" width="24"></iconify-icon>
- Send
- </a>
- </div>
-
- <button class="btn btn-ghost btn-sm w-full" onclick={refresh}>
- <iconify-icon noobserver icon="ph:arrows-clockwise-bold" width="20"></iconify-icon>
- Refresh
- </button>
-
- <div class="divider"></div>
-
- <div class="space-y-2">
- <div class="text-sm text-secondary">Your ARK Address</div>
- <div
- class="text-xs break-all bg-base-200 p-3 rounded-lg cursor-pointer hover:bg-base-300"
- onclick={() => copy(address)}
- >
- {address}
- </div>
- </div>
-
- <div class="space-y-2">
- <div class="text-sm text-secondary">Backup Key</div>
- {#if showNsec}
- <div
- class="text-xs break-all bg-warning/20 p-3 rounded-lg cursor-pointer border border-warning"
- onclick={copyNsec}
- >
- {nsec}
- </div>
- <div class="text-xs text-warning">⚠️ Keep this secret! Anyone with this key can spend your funds.</div>
- {:else}
- <button class="btn btn-warning btn-sm" onclick={revealNsec}>
- <iconify-icon noobserver icon="ph:eye-bold" width="20"></iconify-icon>
- Reveal nsec
- </button>
- {/if}
- </div>
- {/if}
- </div>
-</div>
diff --git a/src/routes/(app)/invoice/[id]/+layout.server.ts b/src/routes/(app)/invoice/[id]/+layout.server.ts
index a18dad4e..ab41dddc 100644
--- a/src/routes/(app)/invoice/[id]/+layout.server.ts
+++ b/src/routes/(app)/invoice/[id]/+layout.server.ts
@@ -11,7 +11,6 @@ export async function load({ cookies, depends, params, url, parent }) {
if (id) {
invoice = await get(`/invoice/${id}`);
- console.log("INV", invoice);
const options = !!url.searchParams.get("options");
let { amount, pending, received } = invoice;
amount = parseInt(amount);
diff --git a/src/routes/(app)/send/ark/[address]/+page.svelte b/src/routes/(app)/send/ark/[address]/+page.svelte
index 6ff6ed58..4f355ec1 100644
--- a/src/routes/(app)/send/ark/[address]/+page.svelte
+++ b/src/routes/(app)/send/ark/[address]/+page.svelte
@@ -6,6 +6,7 @@
import { page } from "$app/stores";
import { rate } from "$lib/store";
import { loc, fail, s } from "$lib/utils";
+ import { getWallet } from "$lib/ark";
let { data } = $props();
@@ -31,6 +32,8 @@
};
let send = async () => {
+ console.log("SENDING", a);
+ let wallet = await getWallet();
const txid = await wallet.sendBitcoin({
address,
amount,