aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-02-03 13:46:15 -0800
committerAdam Soltys <[email protected]>2026-02-11 15:34:01 -0800
commit918f4b29bc66be343914fd4c9284375825c57fdf (patch)
tree68f1b93ee8f1d60400988fd71231295ca886bad6 /src
parent44f09f89eb8f69dbb9bba76e0a55125093e7ecc0 (diff)
downloadcoinos-ui-918f4b29bc66be343914fd4c9284375825c57fdf.tar.gz
coinos-ui-918f4b29bc66be343914fd4c9284375825c57fdf.zip
cleanup
Diffstat (limited to 'src')
-rw-r--r--src/components/Account.svelte4
-rw-r--r--src/components/AppForm.svelte4
-rw-r--r--src/components/LocationsMap.svelte42
-rw-r--r--src/components/Nostr.svelte6
-rw-r--r--src/components/Slider.svelte3
-rw-r--r--src/components/Success.svelte62
-rw-r--r--src/lib/ark.ts5
-rw-r--r--src/lib/nostr.ts39
-rw-r--r--src/lib/parse.ts8
-rw-r--r--src/lib/utils.ts2
-rw-r--r--src/routes/(app)/account/[id]/+page.svelte2
-rw-r--r--src/routes/(app)/account/ark/+page.svelte6
-rw-r--r--src/routes/(app)/account/pass/+page.svelte2
-rw-r--r--src/routes/(app)/firehose/+page.svelte2
-rw-r--r--src/routes/(app)/messages/[recipient]/+page.svelte2
-rw-r--r--src/routes/(app)/pos/+page.svelte6
-rw-r--r--src/routes/(app)/printer/+page.svelte6
-rw-r--r--src/routes/(app)/scan/+page.svelte10
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte14
19 files changed, 166 insertions, 59 deletions
diff --git a/src/components/Account.svelte b/src/components/Account.svelte
index 7c231219..12fa8100 100644
--- a/src/components/Account.svelte
+++ b/src/components/Account.svelte
@@ -7,7 +7,6 @@
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();
@@ -43,7 +42,8 @@
}
};
- let submitPassword = () => {
+ let submitPassword = async () => {
+ const { decrypt } = await import("nostr-tools/nip49");
$arkkey = hex.encode(decrypt(seed, password));
passwordPrompt = false;
if (pendingUrl) {
diff --git a/src/components/AppForm.svelte b/src/components/AppForm.svelte
index f5b8afaa..f9491f38 100644
--- a/src/components/AppForm.svelte
+++ b/src/components/AppForm.svelte
@@ -5,7 +5,6 @@
import AmountField from "$comp/AmountField.svelte";
import Numpad from "$comp/Numpad.svelte";
import Toggle from "$comp/Toggle.svelte";
- import { getPublicKey } from "nostr-tools";
import { onMount, tick } from "svelte";
import { bytesToHex, randomBytes } from "@noble/hashes/utils.js";
import { goto } from "$app/navigation";
@@ -35,8 +34,9 @@
if (!budget_renewal) budget_renewal = "never";
});
- let generate = () => {
+ let generate = async () => {
secret = bytesToHex(randomBytes(32));
+ const { getPublicKey } = await import("nostr-tools");
pubkey = getPublicKey(secret);
};
diff --git a/src/components/LocationsMap.svelte b/src/components/LocationsMap.svelte
index 5de5ac56..eec704a8 100644
--- a/src/components/LocationsMap.svelte
+++ b/src/components/LocationsMap.svelte
@@ -4,8 +4,6 @@
import Popup from "$comp/Popup.svelte";
import { back } from "$lib/utils";
- import "maplibre-gl/dist/maplibre-gl.css";
-
let { locations } = $props();
let map;
let mapContainer = $state(),
@@ -172,10 +170,46 @@
let locationMarkers = {};
let popups = {};
let counter = 0;
+ let maplibrePromise;
+
+ const loadMaplibre = async () => {
+ if (window.maplibregl) return window.maplibregl;
+ if (maplibrePromise) return maplibrePromise;
+
+ maplibrePromise = new Promise((resolve, reject) => {
+ const existing = document.querySelector("script[data-maplibre]");
+ if (existing) {
+ if (window.maplibregl) return resolve(window.maplibregl);
+ existing.addEventListener("load", () => resolve(window.maplibregl));
+ existing.addEventListener("error", reject);
+ return;
+ }
+
+ const css = document.createElement("link");
+ css.rel = "stylesheet";
+ css.href =
+ "https://unpkg.com/[email protected]/dist/maplibre-gl.css";
+ document.head.appendChild(css);
+
+ const script = document.createElement("script");
+ script.src =
+ "https://unpkg.com/[email protected]/dist/maplibre-gl.js";
+ script.async = true;
+ script.defer = true;
+ script.dataset.maplibre = "true";
+ script.onload = () => resolve(window.maplibregl);
+ script.onerror = reject;
+ document.head.appendChild(script);
+ });
+
+ return maplibrePromise;
+ };
- onMount(() => {
+ onMount(async () => {
if (browser) {
- import("maplibre-gl").then(({ default: maplibre }) => {
+ await tick();
+ if (!mapContainer) return;
+ loadMaplibre().then((maplibre) => {
map = new maplibre.Map({
container: mapContainer,
style: "https://tiles.stadiamaps.com/styles/stamen_toner.json",
diff --git a/src/components/Nostr.svelte b/src/components/Nostr.svelte
index fc85100c..4f45da9f 100644
--- a/src/components/Nostr.svelte
+++ b/src/components/Nostr.svelte
@@ -40,6 +40,11 @@
let connectUrl = $state();
let nostrConnect = async () => {
+ const { Relay } = await import("nostr-tools/relay");
+ const { nip04, generateSecretKey, getPublicKey } = await import(
+ "nostr-tools"
+ );
+ const { getConversationKey, decrypt } = await import("nostr-tools/nip44");
let connectionSecret = crypto.randomUUID();
let sk = generateSecretKey();
@@ -89,6 +94,7 @@
};
let nsecSign = async () => {
+ const { nip19, getPublicKey } = await import("nostr-tools");
let sk;
if (nsec.startsWith("nsec")) sk = nip19.decode(nsec).data as Uint8Array;
else sk = hexToBytes(nsec);
diff --git a/src/components/Slider.svelte b/src/components/Slider.svelte
index 401b415a..5b1573f7 100644
--- a/src/components/Slider.svelte
+++ b/src/components/Slider.svelte
@@ -15,8 +15,7 @@
{min}
{max}
bind:value
- class="range"
+ class="range w-full"
oninput={handle}
/>
-
diff --git a/src/components/Success.svelte b/src/components/Success.svelte
index b2e126b3..d7561081 100644
--- a/src/components/Success.svelte
+++ b/src/components/Success.svelte
@@ -2,9 +2,9 @@
import { browser } from "$app/environment";
import { scale } from "svelte/transition";
import Amount from "$comp/Amount.svelte";
- import { Confetti } from "svelte-confetti";
const { amount, tip, rate, currency, locale, title } = $props();
+ let ConfettiComp = $state(null);
let loaded = $state(false);
$effect(() => {
if (browser)
@@ -12,38 +12,46 @@
loaded = true;
});
});
+
+ $effect(async () => {
+ if (!browser || !loaded || ConfettiComp) return;
+ const mod = await import("svelte-confetti");
+ ConfettiComp = mod.Confetti;
+ });
</script>
<div class="text-center mt-20 md:mt-0">
{#if loaded}
<div class="relative flex justify-center">
<div class="absolute top-64 pointer-events-none">
- <Confetti
- amount="20"
- size="40"
- duration="1600"
- delay={[0, 500]}
- fallDistance="50px"
- colorArray={["url(/images/bolt.svg)"]}
- />
- <Confetti
- amount="40"
- delay={[0, 500]}
- size="15"
- fallDistance="50px"
- duration="1600"
- colorArray={[
- "#FFD700", // Gold
- "#FF6F61", // Coral
- "#6BCB77", // Mint green
- "#4D96FF", // Light blue
- "#FF9CEE", // Light pink
- "#FFD580", // Soft orange
- "#87CEEB", // Sky blue
- "#FFB6C1", // Light coral pink
- "#C1C7FF", // Lavender
- ]}
- />
+ {#if ConfettiComp}
+ <ConfettiComp
+ amount="20"
+ size="40"
+ duration="1600"
+ delay={[0, 500]}
+ fallDistance="50px"
+ colorArray={["url(/images/bolt.svg)"]}
+ />
+ <ConfettiComp
+ amount="40"
+ delay={[0, 500]}
+ size="15"
+ fallDistance="50px"
+ duration="1600"
+ colorArray={[
+ "#FFD700", // Gold
+ "#FF6F61", // Coral
+ "#6BCB77", // Mint green
+ "#4D96FF", // Light blue
+ "#FF9CEE", // Light pink
+ "#FFD580", // Soft orange
+ "#87CEEB", // Sky blue
+ "#FFB6C1", // Light coral pink
+ "#C1C7FF", // Lavender
+ ]}
+ />
+ {/if}
</div>
</div>
diff --git a/src/lib/ark.ts b/src/lib/ark.ts
index b1098ee3..d0f16d78 100644
--- a/src/lib/ark.ts
+++ b/src/lib/ark.ts
@@ -1,14 +1,17 @@
import { persistLocal } from "$lib/store";
import { post } from "$lib/utils";
-import { SingleKey, Wallet } from "@arkade-os/sdk";
import { get } from "svelte/store";
export const arkServerUrl = "http://localhost:7070";
export const arkkey = persistLocal("arkkey", "");
+let arkSdkPromise: Promise<typeof import("@arkade-os/sdk")> | undefined;
+const loadArkSdk = () => (arkSdkPromise ||= import("@arkade-os/sdk"));
+
export const getWallet = async () => {
const key = get(arkkey);
if (!key) return;
+ const { SingleKey, Wallet } = await loadArkSdk();
const identity = SingleKey.fromHex(key);
return Wallet.create({
diff --git a/src/lib/nostr.ts b/src/lib/nostr.ts
index 6343bc9e..85c90051 100644
--- a/src/lib/nostr.ts
+++ b/src/lib/nostr.ts
@@ -21,10 +21,18 @@ import { decrypt as nip44decrypt, getConversationKey } from "nostr-tools/nip44";
import { Relay } from "nostr-tools/relay";
import { get } from "svelte/store";
-import {
- decrypt as nip49decrypt,
- encrypt as nip49encrypt,
-} from "nostr-tools/nip49";
+let nostrToolsPromise:
+ | Promise<typeof import("nostr-tools")>
+ | undefined;
+let nip44Promise: Promise<typeof import("nostr-tools/nip44")> | undefined;
+let relayPromise: Promise<typeof import("nostr-tools/relay")> | undefined;
+let nip49Promise: Promise<typeof import("nostr-tools/nip49")> | undefined;
+
+const loadNostrTools = () =>
+ (nostrToolsPromise ||= import("nostr-tools"));
+const loadNip44 = () => (nip44Promise ||= import("nostr-tools/nip44"));
+const loadRelay = () => (relayPromise ||= import("nostr-tools/relay"));
+const loadNip49 = () => (nip49Promise ||= import("nostr-tools/nip49"));
type User = {
[key: string]: any;
@@ -38,6 +46,7 @@ type EncryptParams = {
export const encrypt = async ({ message, recipient, user }: EncryptParams) => {
const sk = await getPrivateKey(user);
+ const { nip04 } = await loadNostrTools();
return nip04.encrypt(sk, recipient, message);
};
@@ -48,6 +57,7 @@ export const decrypt = async ({ event, user }) => {
if (cache[id]) return cache[id];
if (pubkey === user.pubkey) pubkey = event.tags[0][1];
+ const { nip04 } = await loadNostrTools();
const message = await nip04.decrypt(
await getPrivateKey(user),
pubkey,
@@ -68,6 +78,7 @@ export const getPrivateKey = async (user: User): Promise<Uint8Array> => {
if (browser) {
k = localStorage.getItem("nsec");
if (k) {
+ const { nip19 } = await loadNostrTools();
return nip19.decode(k).data as Uint8Array;
}
}
@@ -75,38 +86,45 @@ export const getPrivateKey = async (user: User): Promise<Uint8Array> => {
const { nsec } = user;
if (nsec) {
+ const { decrypt: nip49decrypt } = await loadNip49();
k = nip49decrypt(nsec, await getPassword());
} else {
throw new Error("nsec not available");
}
+ const { nip19 } = await loadNostrTools();
localStorage.setItem("nsec", nip19.nsecEncode(k));
return k;
};
-const decodeNsec = (nsec: string): Uint8Array => {
+const decodeNsec = async (nsec: string): Promise<Uint8Array> => {
+ const { nip19 } = await loadNostrTools();
const { type, data } = nip19.decode(nsec);
if (type === "nsec" && data instanceof Uint8Array) return data;
throw new Error("invalid nsec");
};
export const getNsec = async (user: User) => {
+ const { nip19 } = await loadNostrTools();
return nip19.nsecEncode(await getPrivateKey(user));
};
export const setNsec = async (user: User, nsec: string) => {
- user.pubkey = getPublicKey(decodeNsec(nsec));
+ const { getPublicKey } = await loadNostrTools();
+ user.pubkey = getPublicKey(await decodeNsec(nsec));
user.nsec = await encryptNsec(nsec);
};
export const encryptNsec = async (nsec: string) => {
- const d = decodeNsec(nsec);
+ const { encrypt: nip49encrypt } = await loadNip49();
+ const d = await decodeNsec(nsec);
return nip49encrypt(d, await getPassword());
};
export const sign = async (event, user) => {
if (user?.nsec && !get($signer)?.ready) {
const sk = await getPrivateKey(user);
+ const { getPublicKey } = await loadNostrTools();
$signer.set({
method: "nsec",
@@ -154,6 +172,7 @@ const signingMethods = {
params: [JSON.stringify(event)],
};
+ const { nip04, finalizeEvent } = await loadNostrTools();
const content = await nip04.encrypt(sk, pk, JSON.stringify(signEvent));
const signedSignEvent = finalizeEvent(
@@ -167,6 +186,7 @@ const signingMethods = {
sk,
);
+ const { Relay } = await loadRelay();
const relay = await Relay.connect(nostrConnectRelay);
relay.publish(signedSignEvent);
@@ -177,8 +197,11 @@ const signingMethods = {
try {
let response;
try {
+ const { nip04 } = await loadNostrTools();
response = JSON.parse(await nip04.decrypt(sk, pk, event.content));
} catch (e) {
+ const { getConversationKey, decrypt: nip44decrypt } =
+ await loadNip44();
const ck = await getConversationKey(sk, pk);
response = JSON.parse(await nip44decrypt(event.content, ck));
}
@@ -193,6 +216,7 @@ const signingMethods = {
},
async nsec(event, { sk }) {
+ const { finalizeEvent } = await loadNostrTools();
return finalizeEvent(event, sk);
},
@@ -202,6 +226,7 @@ const signingMethods = {
async signer(event, { pubkey, sig }) {
event.pubkey = pubkey;
+ const { getEventHash } = await loadNostrTools();
const signedEvent = {
...event,
id: getEventHash(event),
diff --git a/src/lib/parse.ts b/src/lib/parse.ts
index bbcab429..8520c27a 100644
--- a/src/lib/parse.ts
+++ b/src/lib/parse.ts
@@ -2,7 +2,12 @@ import { PUBLIC_DOMAIN } from "$env/static/public";
import { decode } from "$lib/bip21";
import { auth, get, isLiquid, post, sats } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
-import { validate } from "bitcoin-address-validation";
+
+let validatePromise:
+ | Promise<typeof import("bitcoin-address-validation")>
+ | undefined;
+const loadValidate = () =>
+ (validatePromise ||= import("bitcoin-address-validation"));
export default async (s, host, cookies) => {
if (!s) return;
@@ -49,6 +54,7 @@ export default async (s, host, cookies) => {
} = decode(t));
}
+ const { validate } = await loadValidate();
if (validate(t) || isLiquid(t)) {
let r = `/send/bitcoin/${t}`;
if (amount) r += `/${Math.round(amount * sats)}`;
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index d3333280..33737b50 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -11,7 +11,6 @@ import {
differenceInMinutes,
differenceInSeconds,
} from "date-fns";
-import { decrypt } from "nostr-tools/nip49";
import { get as getStore } from "svelte/store";
export function scroll(section: any) {
@@ -207,6 +206,7 @@ export const login = async (
cookies.set("token", token, opts);
if (u.nsec) {
try {
+ const { decrypt } = await import("nostr-tools/nip49");
cookies.set("sk", bytesToHex(decrypt(u.nsec, user.password)), {
...opts,
httpOnly: false,
diff --git a/src/routes/(app)/account/[id]/+page.svelte b/src/routes/(app)/account/[id]/+page.svelte
index 258912d6..bda81cbc 100644
--- a/src/routes/(app)/account/[id]/+page.svelte
+++ b/src/routes/(app)/account/[id]/+page.svelte
@@ -6,7 +6,6 @@
import { copy, fail, focus, post } from "$lib/utils";
import { enhance } from "$app/forms";
import { t } from "$lib/translations";
- import { decrypt } from "nostr-tools/nip49";
import { entropyToMnemonic, mnemonicToSeed } from "@scure/bip39";
import { wordlist } from "@scure/bip39/wordlists/english.js";
import {
@@ -27,6 +26,7 @@
let submit = $state(async () => {
toggle();
+ const { decrypt } = await import("nostr-tools/nip49");
let entropy = await decrypt(seed, password);
mnemonic = entropyToMnemonic(entropy, wordlist);
});
diff --git a/src/routes/(app)/account/ark/+page.svelte b/src/routes/(app)/account/ark/+page.svelte
index 4036d140..6d16556c 100644
--- a/src/routes/(app)/account/ark/+page.svelte
+++ b/src/routes/(app)/account/ark/+page.svelte
@@ -3,13 +3,10 @@
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();
@@ -35,6 +32,8 @@
});
let generateKey = async () => {
+ const { nip19 } = await import("nostr-tools");
+ const { SingleKey, Wallet } = await import("@arkade-os/sdk");
privateKey = bytesToHex(randomBytes(32));
nsec = nip19.nsecEncode(hex.decode(privateKey));
showNsec = false;
@@ -70,6 +69,7 @@
try {
// Encrypt the private key using NIP-49
+ const { encrypt } = await import("nostr-tools/nip49");
let seed = await encrypt(hex.decode(privateKey), password);
await post("/account", { name, seed, type, arkAddress });
diff --git a/src/routes/(app)/account/pass/+page.svelte b/src/routes/(app)/account/pass/+page.svelte
index 7de18184..5e681033 100644
--- a/src/routes/(app)/account/pass/+page.svelte
+++ b/src/routes/(app)/account/pass/+page.svelte
@@ -5,7 +5,6 @@
import { t } from "$lib/translations";
import { mnemonic } from "$lib/store";
import Spinner from "$comp/Spinner.svelte";
- import { encrypt } from "nostr-tools/nip49";
import {
mnemonicToSeed,
mnemonicToEntropy,
@@ -41,6 +40,7 @@
}
try {
+ const { encrypt } = await import("nostr-tools/nip49");
let seed = await encrypt(
mnemonicToEntropy($mnemonic, wordlist),
password,
diff --git a/src/routes/(app)/firehose/+page.svelte b/src/routes/(app)/firehose/+page.svelte
index 1cf2324e..d56e6425 100644
--- a/src/routes/(app)/firehose/+page.svelte
+++ b/src/routes/(app)/firehose/+page.svelte
@@ -2,7 +2,6 @@
import Event from "$comp/Event.svelte";
import { get, post } from "$lib/utils";
import { onMount } from "svelte";
- import { Relay } from "nostr-tools/relay";
import { ignore } from "$lib/store";
let events = $state([]);
@@ -19,6 +18,7 @@
};
onMount(async () => {
+ const { Relay } = await import("nostr-tools/relay");
const relay = await Relay.connect("wss://relay.primal.net");
const subscription = relay.subscribe([{ kinds: [1], limit: 20 }], {
async onevent(event) {
diff --git a/src/routes/(app)/messages/[recipient]/+page.svelte b/src/routes/(app)/messages/[recipient]/+page.svelte
index 9c916d3d..b47f9089 100644
--- a/src/routes/(app)/messages/[recipient]/+page.svelte
+++ b/src/routes/(app)/messages/[recipient]/+page.svelte
@@ -13,7 +13,6 @@
import { sign, send, encrypt, decrypt } from "$lib/nostr";
import { event as e, password } from "$lib/store";
import { tick, onMount } from "svelte";
- import { getEventHash } from "nostr-tools";
let { data } = $props();
@@ -90,6 +89,7 @@
recipient: recipient.pubkey,
user,
});
+ const { getEventHash } = await import("nostr-tools");
event.id = getEventHash(event);
await sign(event);
await send(event);
diff --git a/src/routes/(app)/pos/+page.svelte b/src/routes/(app)/pos/+page.svelte
index 2a072f5a..199cef43 100644
--- a/src/routes/(app)/pos/+page.svelte
+++ b/src/routes/(app)/pos/+page.svelte
@@ -1,6 +1,5 @@
<script>
import { enhance } from "$app/forms";
- import { ESPLoader, Transport } from "esptool-js";
import { hex } from "@scure/base";
// Convert Uint8Array → JS "binary string" in safe chunks
@@ -28,6 +27,8 @@
let chip, transport;
let connected = $state(false);
let portInfo = $state("");
+ let ESPLoader;
+ let Transport;
// --- Existing config path (generated server-side to hex in form.bytes) ---
let bytes = $derived(form ? hex.decode(form.bytes) : undefined);
@@ -49,6 +50,9 @@
let connect = async () => {
try {
+ if (!ESPLoader || !Transport) {
+ ({ ESPLoader, Transport } = await import("esptool-js"));
+ }
const device = await navigator.serial.requestPort({});
transport = new Transport(device, true);
esploader = new ESPLoader({
diff --git a/src/routes/(app)/printer/+page.svelte b/src/routes/(app)/printer/+page.svelte
index c1e6ee82..c9295a54 100644
--- a/src/routes/(app)/printer/+page.svelte
+++ b/src/routes/(app)/printer/+page.svelte
@@ -1,6 +1,5 @@
<script>
import { enhance } from "$app/forms";
- import { ESPLoader, Transport } from "esptool-js";
import { hex } from "@scure/base";
function bs(uint8Array) {
@@ -29,9 +28,14 @@
let data = $derived(form ? hex.decode(form.data) : undefined);
let chip, transport;
+ let ESPLoader;
+ let Transport;
// let data = $state();
let connect = async () => {
try {
+ if (!ESPLoader || !Transport) {
+ ({ ESPLoader, Transport } = await import("esptool-js"));
+ }
let device = await navigator.serial.requestPort({});
transport = new Transport(device, true);
diff --git a/src/routes/(app)/scan/+page.svelte b/src/routes/(app)/scan/+page.svelte
index b21a7458..655346c8 100644
--- a/src/routes/(app)/scan/+page.svelte
+++ b/src/routes/(app)/scan/+page.svelte
@@ -1,15 +1,15 @@
<script>
import { tick } from "svelte";
import Icon from "$comp/Icon.svelte";
- import QrScanner from "qr-scanner";
import { onMount, onDestroy } from "svelte";
import { back } from "$lib/utils";
import { goto } from "$app/navigation";
- import { BarcodeDetector } from "barcode-detector/ponyfill";
let scanner,
vid = $state(),
resizing;
+ let QrScanner;
+ let BarcodeDetector;
let resize = () => {
if (resizing) clearTimeout(resizing);
@@ -17,6 +17,12 @@
};
let initialize = async () => {
+ if (!QrScanner) {
+ ({ default: QrScanner } = await import("qr-scanner"));
+ }
+ if (!BarcodeDetector) {
+ ({ BarcodeDetector } = await import("barcode-detector/ponyfill"));
+ }
if (scanner) {
scanner.stop();
await new Promise((r) => setTimeout(r, 1000));
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 ac904304..70e68c79 100644
--- a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
+++ b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
@@ -42,13 +42,25 @@
};
let signTx = async () => {
+ const { decrypt } = await import("nostr-tools/nip49");
+ const [
+ { Transaction },
+ { HDKey },
+ { entropyToMnemonic, mnemonicToSeed },
+ { wordlist },
+ ] = await Promise.all([
+ import("@scure/btc-signer"),
+ import("@scure/bip32"),
+ import("@scure/bip39"),
+ import("@scure/bip39/wordlists/english"),
+ ]);
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));
+ let tx = Transaction.fromRaw(decode(hex));
for (let [i, input] of tx.inputs.entries()) {
let { witnessUtxo, path } = inputs[i];