aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-02-28 18:30:33 -0800
committerAdam Soltys <[email protected]>2026-02-28 18:30:33 -0800
commit41467c51e2def5c8932e1dd967f3cfe04e0cc563 (patch)
treeff2322fc5573ac32c3a6420d705bddd7fefc15f0 /src/lib
parentba715da66afed730180750b567cc3b956a0c9181 (diff)
downloadcoinos-ui-41467c51e2def5c8932e1dd967f3cfe04e0cc563.tar.gz
coinos-ui-41467c51e2def5c8932e1dd967f3cfe04e0cc563.zip
service worker for ark wallet refresh
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ark.ts64
1 files changed, 62 insertions, 2 deletions
diff --git a/src/lib/ark.ts b/src/lib/ark.ts
index 1a779f32..c5212f70 100644
--- a/src/lib/ark.ts
+++ b/src/lib/ark.ts
@@ -1,6 +1,6 @@
import { PUBLIC_COINOS_NETWORK } from "$env/static/public";
import { persistLocal } from "$lib/store";
-import { post } from "$lib/utils";
+import { post, versions } from "$lib/utils";
import { get } from "svelte/store";
export const arkServerUrl = {
@@ -64,6 +64,31 @@ export const getWallet = async () => {
return walletInstance;
};
+export const autoUnlockArk = async () => {
+ if (get(arkkey)) return;
+ const { getWalletEntropy } = await import("$lib/walletEntropy");
+ const entropy = await getWalletEntropy();
+ if (!entropy) return;
+ try {
+ const [{ HDKey }, { entropyToMnemonic, mnemonicToSeed }, { wordlist }] = await Promise.all([
+ import("@scure/bip32"),
+ import("@scure/bip39"),
+ import("@scure/bip39/wordlists/english.js"),
+ ]);
+ const { bytesToHex } = await import("@noble/hashes/utils.js");
+ const ent = new Uint8Array(entropy).slice(0, 16);
+ const mnemonic = entropyToMnemonic(ent, wordlist);
+ const seed = await mnemonicToSeed(mnemonic);
+ const master = HDKey.fromMasterSeed(seed, versions);
+ const child = master.derive("m/86'/0'/0'/0/0");
+ const key = bytesToHex(child.privateKey!);
+ arkkey.set(key);
+ } catch (e) {
+ console.error("Ark auto-unlock failed:", e);
+ }
+};
+
+
const toHex = (bytes: Uint8Array) =>
Array.from(bytes)
.map((b) => b.toString(16).padStart(2, "0"))
@@ -339,7 +364,7 @@ export const sendArk = async (address: string, amount: number) => {
const freshBalance = await wallet.getBalance();
const preSendTotal = (freshBalance.available || 0) + (freshBalance.preconfirmed || 0);
if (freshBalance.available < amount) {
- throw new Error(`Insufficient funds: ${freshBalance.available} available, need ${amount}`);
+ throw new Error(`Insufficient funds: ${freshBalance.available} available, need ${amount}\nLocked balance: ${freshBalance.boarding || 0} boarding, ${freshBalance.preconfirmed || 0} preconfirmed, ${freshBalance.recoverable || 0} recoverable`);
}
let txid;
@@ -463,3 +488,38 @@ export const settle = async () => {
const vtxos = await wallet.getVtxos({ spendableOnly: false });
if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey));
};
+
+// Service Worker wallet for background fund notifications
+let swWallet: any;
+let swWalletKey: string | undefined;
+
+export const getServiceWorkerWallet = async () => {
+ const key = get(arkkey);
+ if (!key) {
+ await cleanupServiceWorkerWallet();
+ return;
+ }
+ if (swWallet && swWalletKey === key) return swWallet;
+ if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) return;
+
+ try {
+ const { ServiceWorkerWallet, SingleKey } = await loadArkSdk();
+ swWallet = await ServiceWorkerWallet.setup({
+ serviceWorkerPath: "/service-worker.js",
+ arkServerUrl: arkServerUrl!,
+ identity: SingleKey.fromHex(key),
+ });
+ swWalletKey = key;
+ return swWallet;
+ } catch (e) {
+ console.error("[ark] Service worker wallet init failed:", e);
+ }
+};
+
+export const cleanupServiceWorkerWallet = async () => {
+ if (swWallet) {
+ try { await swWallet.clear(); } catch {}
+ }
+ swWallet = undefined;
+ swWalletKey = undefined;
+};